অ্যান্ড্রয়েডে কীভাবে মসৃণ চিত্র ঘোরানো যায়?


217

আমি RotateAnimationএমন একটি চিত্র ঘোরানোর জন্য ব্যবহার করছি যা আমি অ্যান্ড্রয়েডে একটি কাস্টম চক্রীয় স্পিনার হিসাবে ব্যবহার করছি। আমার rotate_indefinitely.xmlফাইলটি এখানে আমি রেখেছি res/anim/:

<?xml version="1.0" encoding="UTF-8"?>
<rotate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="infinite"
    android:duration="1200" />    

আমি যখন এটি আমার ImageViewব্যবহারের জন্য প্রয়োগ করি তখন AndroidUtils.loadAnimation()এটি দুর্দান্ত কাজ করে!

spinner.startAnimation( 
    AnimationUtils.loadAnimation(activity, R.anim.rotate_indefinitely) );

একটি সমস্যা হ'ল চিত্রের ঘূর্ণনটি প্রতিটি চক্রের শীর্ষে থেমে আছে বলে মনে হচ্ছে।

অন্য কথায়, ছবিটি 360 ডিগ্রি ঘোরায়, সংক্ষিপ্ত বিরতি দেয়, তারপরে আবার 360 ডিগ্রি ঘোরানো হয় ইত্যাদি

আমি সন্দেহ করি যে সমস্যাটি হ'ল অ্যানিমেশনটি android:iterpolator="@android:anim/accelerate_interpolator"( AccelerateInterpolator) এর মতো একটি ডিফল্ট ইন্টারপোলটর ব্যবহার করছে তবে অ্যানিমেশনটি ফাঁকা না দেওয়ার জন্য কীভাবে তা জানাতে হবে তা আমি জানি না।

কীভাবে আমি আমার অ্যানিমেশন চক্রটি সাবলীলভাবে তৈরি করতে আন্তঃবিসরণ বন্ধ করতে পারি (যদি তা সত্যিই সমস্যা হয়)

উত্তর:


199

আপনি এক্সিলারেটর ইন্টারপোলটার সম্পর্কে ঠিক বলেছেন; পরিবর্তে আপনার লিনিয়ারআইন্টারপোলটার ব্যবহার করা উচিত।

আপনি android.R.anim.linear_interpolatorনিজের অ্যানিমেশন XML ফাইল থেকে অন্তর্নির্মিতটি ব্যবহার করতে পারেন android:interpolator="@android:anim/linear_interpolator"

অথবা আপনি আপনার প্রকল্পে নিজের এক্সএমএল ইন্টারপোলেশন ফাইল তৈরি করতে পারেন, উদাহরণস্বরূপ নাম দিন res/anim/linear_interpolator.xml:

<?xml version="1.0" encoding="utf-8"?>
<linearInterpolator xmlns:android="http://schemas.android.com/apk/res/android" />

এবং আপনার অ্যানিমেশনটি এক্সএমএল যুক্ত করুন:

android:interpolator="@anim/linear_interpolator"

বিশেষ দ্রষ্টব্য: আপনার ঘোরানো অ্যানিমেশনটি যদি কোনও সেটের অভ্যন্তরে থাকে তবে ইন্টারপোলটারটি সেট করা কাজ করবে বলে মনে হয় না। শীর্ষস্থানীয় ঘোরানো তৈরি এটি ঠিক করে দেয়। (এটি আপনার সময় সাশ্রয় করবে))


1
এটি কারণ ইন্টারপোলটারকে ভুল বানান করা হয়েছিল (কোনও "এন" নয়)। আপনার নিজের তৈরি করার দরকার নেই
কিংপিন

25
আমি লিনিয়ার সহ প্রতিটি ইন্টারপোলটার উপলব্ধ করার চেষ্টা করেছি এবং প্রতিটি চক্রের শুরুতে আমি এই সামান্য "হিচা" পাই।
অ্যাডাম রাবুং

11
আপনার ঘোরানো অ্যানিমেশনটি যদি কোনও সেটের অভ্যন্তরে থাকে তবে ইন্টারপোলটারটি সেট করা কাজ করবে বলে মনে হয় না। শীর্ষস্থানীয়
ঘোরানোটি

আরে, আপনি যদি প্রতিটি অ্যানিমেশনগুলির মধ্যে ছোট "বিরতি" ছাড়াই প্রকৃতপক্ষে ত্বক_পরিবর্তন_আপনার ব্যবহার করতে চান?
agonist_

90

আমারও এই সমস্যাটি ছিল, এবং সাফল্য ছাড়াই xML এ লিনিয়ার ইন্টারপোলটার সেট করার চেষ্টা করেছি। আমার পক্ষে যে সমাধানটি কাজ করেছিল তা হ'ল কোডটিতে রোটেটএনিমেশন হিসাবে অ্যানিমেশন তৈরি করা।

RotateAnimation rotate = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(5000);
rotate.setInterpolator(new LinearInterpolator());

ImageView image= (ImageView) findViewById(R.id.imageView);

image.startAnimation(rotate);

9
আপনি যদি অ্যানিমেশনটি শেষে ওরিয়েন্টেশনে থাকতে চান তবে যুক্ত করুনrotate.setFillAfter(true);
ফোনিক্স

4
আপনি যদি অ্যানিমেশনটি কোনও শেষ না দিয়ে স্থায়ীভাবে থাকতে চান তবে যুক্ত করুনrotate.setRepeatCount(Animation.INFINITE);
আহমাদেবিলব্বি

38

এটি কাজ করে

<?xml version="1.0" encoding="UTF-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1600"
    android:fromDegrees="0"
    android:interpolator="@android:anim/linear_interpolator"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="infinite"
    android:toDegrees="358" />

বিপরীত ঘোরানো:

<?xml version="1.0" encoding="UTF-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1600"
    android:fromDegrees="358"
    android:interpolator="@android:anim/linear_interpolator"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="infinite"
    android:toDegrees="0" />

5
বিপরীতে, কেবল রিপিটকাউন্ট 2 এবং অ্যান্ড্রয়েড সেট করুন: রিপিটমোড = "বিপরীত" - দুটি আলাদা এক্সএমএল ফাইল লাগবে না।
রাউন্ডস্প্যারো হিলিটেক্স

3
358 এবং 359 বা 360 না কেন?
বেহালিত

সংস্থানগুলিতে এই ফাইলটি কোথায় যুক্ত করবেন? অ্যানিমেশন কি এর জন্য আলাদা প্যাকেজ?
abggcv

30

হতে পারে, এরকম কিছু সাহায্য করবে:

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        imageView.animate().rotationBy(360).withEndAction(this).setDuration(3000).setInterpolator(new LinearInterpolator()).start();
    }
};

imageView.animate().rotationBy(360).withEndAction(runnable).setDuration(3000).setInterpolator(new LinearInterpolator()).start();

উপায় দ্বারা, আপনি 360 টিরও বেশি মতো ঘোরান:

imageView.animate().rotationBy(10000)...

নিখুঁতভাবে কাজ করা, ইমেজভিউ।
XcodeNOOB

এটি অ্যানিমেশন শুরু করার জন্য সূক্ষ্ম কাজ, তবে শুরু করার পরে এটি চিত্র ভিউক্লিয়ার অ্যানিমেশন () দ্বারা পরিষ্কার করা হয়নি, আমি স্পর্শ শ্রোতার ইভেন্টে ব্যবহার করেছি
অভিজিৎ


@ প্যান্টগুলি আপনি কিছু শর্তে এন্ডএ্যাকশন (এটি) দিয়ে কল করতে পারেন। শর্তটি মিথ্যা হলে, এন্ডএ্যাকশন সহ (এটি) কল করা হবে না, এবং অ্যানিমেশনটি বন্ধ হওয়া উচিত
ভাইটালি জিংচেনকো



8

প্রোগ্রামিকভাবে ঘূর্ণন অবজেক্ট।

// ঘড়ির কাঁটার বিবর্তন:

    public void rotate_Clockwise(View view) {
        ObjectAnimator rotate = ObjectAnimator.ofFloat(view, "rotation", 180f, 0f);
//        rotate.setRepeatCount(10);
        rotate.setDuration(500);
        rotate.start();
    }

// এন্টি ক্লকওয়াইজ রোটেশন:

 public void rotate_AntiClockwise(View view) {
        ObjectAnimator rotate = ObjectAnimator.ofFloat(view, "rotation", 0f, 180f);
//        rotate.setRepeatCount(10);
        rotate.setDuration(500);
        rotate.start();
    } 

দর্শনটি আপনার ইমেজভিউ বা অন্যান্য উইজেটের অবজেক্ট।

rotate.setRepeatCount (10); আপনার ঘূর্ণন পুনরাবৃত্তি করতে ব্যবহার করুন।

500 আপনার অ্যানিমেশন সময়কাল।


6

<set>এলিমেট - কেটে দেয় এমন <rotate>এলিমে ছাঁটাই সমস্যাটি সমাধান করে!

শালাফিকে ধন্যবাদ!

সুতরাং আপনার আবর্তন_সিসিডব্লিউ.এম.এম.এলগুলি এটিকে দেখতে হবে:

<?xml version="1.0" encoding="utf-8"?>

<rotate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="-360"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="2000"
    android:fillAfter="false"
    android:startOffset="0"
    android:repeatCount="infinite"
    android:interpolator="@android:anim/linear_interpolator"
    />

3

আমি যা চেষ্টা করেছি তা বিবেচনা করেই, মসৃণ রোটেশন অ্যানিমেশনের জন্য কোড (এবং সেটরোটেশন) ব্যবহার করে আমি এটি কাজ করতে পারি না। আমি যেটা শেষ করেছিলাম তা হ'ল ডিগ্রি পরিবর্তনগুলি এত ছোট করা হয়েছিল যে ছোট বিরামগুলি অবিস্মরণীয়। আপনার যদি খুব বেশি ঘোরানোর দরকার না হয় তবে এই লুপটি কার্যকর করার সময়টি নগণ্য। প্রভাবটি একটি মসৃণ ঘূর্ণন:

        float lastDegree = 0.0f;
        float increment = 4.0f;
        long moveDuration = 10;
        for(int a = 0; a < 150; a++)
        {
            rAnim = new RotateAnimation(lastDegree, (increment * (float)a),  Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            rAnim.setDuration(moveDuration);
            rAnim.setStartOffset(moveDuration * a);
            lastDegree = (increment * (float)a);
            ((AnimationSet) animation).addAnimation(rAnim);
        }

আপনি "অ্যানিমেশন" পরিবর্তনশীল ঘোষণা কোথায়?
habষভ সাক্সেনা

3

যেমন হ্যানির উপরে উল্লিখিত হয়েছে লাইনার ইটারপোলটার স্থাপন করা ভাল। তবে ঘূর্ণন যদি কোনও সেটের অভ্যন্তরে থাকে তবে অবশ্যই আপনাকে এন্ড্রয়েড লাগিয়ে রাখতে হবে: এটিকে মসৃণ করতে shareInterpolator = "মিথ্যা"।

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
**android:shareInterpolator="false"**
>
<rotate
    android:interpolator="@android:anim/linear_interpolator"
    android:duration="300"
    android:fillAfter="true"
    android:repeatCount="10"
    android:repeatMode="restart"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%" />
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/linear_interpolator"
    android:duration="3000"
    android:fillAfter="true"
    android:pivotX="50%"
    android:pivotY="50%"
    android:fromXScale="1.0"
    android:fromYScale="1.0"
    android:toXScale="0"
    android:toYScale="0" />
</set>

যদি Sharedinterpolator মিথ্যা না হয়ে থাকে, উপরের কোডটি গ্লিটস দেয়।


3

আপনি যদি আমার মতো সেট অ্যানিমেশন ব্যবহার করেন তবে আপনার সেট ট্যাগের অভ্যন্তরে অন্তরঙ্গন যুক্ত করা উচিত:

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator">

 <rotate
    android:duration="5000"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="infinite"
    android:startOffset="0"
    android:toDegrees="360" />

 <alpha
    android:duration="200"
    android:fromAlpha="0.7"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:toAlpha="1.0" />

</set>

আমার জন্য কাজ করেছে।


3

কোটলিনে:

 ivBall.setOnClickListener(View.OnClickListener {

            //Animate using XML
            // val rotateAnimation = AnimationUtils.loadAnimation(activity, R.anim.rotate_indefinitely)

            //OR using Code
            val rotateAnimation = RotateAnimation(
                    0f, 359f,
                    Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF, 0.5f

            )
            rotateAnimation.duration = 300
            rotateAnimation.repeatCount = 2

            //Either way you can add Listener like this
            rotateAnimation.setAnimationListener(object : Animation.AnimationListener {

                override fun onAnimationStart(animation: Animation?) {
                }

                override fun onAnimationRepeat(animation: Animation?) {
                }

                override fun onAnimationEnd(animation: Animation?) {

                    val rand = Random()
                    val ballHit = rand.nextInt(50) + 1
                    Toast.makeText(context, "ballHit : " + ballHit, Toast.LENGTH_SHORT).show()
                }
            })

            ivBall.startAnimation(rotateAnimation)
        })

1

এটি কি সম্ভব যে আপনি 0 থেকে 360 এ যাওয়ার কারণে আপনি প্রত্যাশার চেয়ে 0/360 এ কিছুটা বেশি সময় ব্যয় করেন? সম্ভবত ডিগ্রিগুলিকে 359 বা 358 এ সেট করা হয়েছে।


1
দুর্দান্ত তত্ত্ব। আমি নিশ্চিত যে এটি তা নয় কারণ গতি / স্লোডাউন বেশ মসৃণ এবং ইচ্ছাকৃতভাবে দেখায়। সেক্ষেত্রে যদিও আমি ডিগ্রিগুলি 358 এ হ্রাস করার চেষ্টা করেছি এবং আচরণে কোনও পরিবর্তনযোগ্য পরিবর্তন হয়নি।
এমএমবি 0

1

পুনরায় চালু হওয়া এড়াতে 360 এরও বেশি ব্যবহার করার চেষ্টা করুন।

আমি 360 এর 3600 ইনসটেড ব্যবহার করি এবং এটি আমার পক্ষে কাজ করে:

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="3600"
    android:interpolator="@android:anim/linear_interpolator"
    android:repeatCount="infinite"
    android:duration="8000"
    android:pivotX="50%"
    android:pivotY="50%" />

0

অ্যান্ড্রয়েডে, আপনি যদি কোনও বস্তু সঞ্জীবিত করতে এবং এটি কোনও অবস্থান 1 থেকে লোকেশন 2 এ স্থানান্তর করতে চান তবে অ্যানিমেশন এপিআই মধ্যবর্তী অবস্থানগুলি (টিউনিং) সনাক্ত করে এবং তারপরে টাইমার ব্যবহার করে উপযুক্ত সময়ে যথাযথ পদক্ষেপের ক্রিয়াগুলি মূল থ্রেডের মধ্যে সারি করে । মূল থ্রেডটি সাধারণত অন্যান্য অনেক কিছুর জন্য ব্যবহৃত হয় - পেন্টিং, ফাইল খোলার জন্য, ব্যবহারকারীর ইনপুটগুলিতে সাড়া দেওয়া ইত্যাদি etc. ভাল লিখিত প্রোগ্রামগুলি সর্বদা ব্যাকগ্রাউন্ড (নন মেইন) থ্রেডগুলিতে যথাসম্ভব অপারেশন করার চেষ্টা করবে তবে আপনি সবসময় মূল থ্রেড ব্যবহার এড়াতে পারবেন না। অপারেশনগুলির জন্য যেগুলি আপনাকে কোনও ইউআই অবজেক্টে চালিত করা প্রয়োজন সর্বদা মূল থ্রেডে করতে হবে। এছাড়াও, অনেকগুলি এপিআই থ্রেড-সুরক্ষার ফর্ম হিসাবে মূল থ্রেডে ফিরে অপারেশনগুলি ফানেল করবে।

ভিউগুলি সমস্ত একই জিইউআই থ্রেডে আঁকা হয় যা সমস্ত ব্যবহারকারীর মিথস্ক্রিয়াতেও ব্যবহৃত হয়।

সুতরাং আপনার যদি GUI দ্রুত আপডেট করার প্রয়োজন হয় বা যদি রেন্ডারিংটি খুব বেশি সময় নেয় এবং ব্যবহারকারীর অভিজ্ঞতাকে প্রভাবিত করে তবে সারফেসভিউ ব্যবহার করুন।

ঘূর্ণন চিত্রের উদাহরণ:

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
    private DrawThread drawThread;

    public MySurfaceView(Context context) {
        super(context);
        getHolder().addCallback(this);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {   
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        drawThread = new DrawThread(getHolder(), getResources());
        drawThread.setRunning(true);
        drawThread.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        drawThread.setRunning(false);
        while (retry) {
            try {
                drawThread.join();
                retry = false;
            } catch (InterruptedException e) {
            }
        }
    }
}


class DrawThread extends Thread{
    private boolean runFlag = false;
    private SurfaceHolder surfaceHolder;
    private Bitmap picture;
    private Matrix matrix;
    private long prevTime;

    public DrawThread(SurfaceHolder surfaceHolder, Resources resources){
        this.surfaceHolder = surfaceHolder;

        picture = BitmapFactory.decodeResource(resources, R.drawable.icon);

        matrix = new Matrix();
        matrix.postScale(3.0f, 3.0f);
        matrix.postTranslate(100.0f, 100.0f);

        prevTime = System.currentTimeMillis();
    }

    public void setRunning(boolean run) {
        runFlag = run;
    }

    @Override
    public void run() {
        Canvas canvas;
        while (runFlag) {
            long now = System.currentTimeMillis();
            long elapsedTime = now - prevTime;
            if (elapsedTime > 30){

                prevTime = now;
                matrix.preRotate(2.0f, picture.getWidth() / 2, picture.getHeight() / 2);
            }
            canvas = null;
            try {
                canvas = surfaceHolder.lockCanvas(null);
                synchronized (surfaceHolder) {
                    canvas.drawColor(Color.BLACK);
                    canvas.drawBitmap(picture, matrix, null);
                }
            } 
            finally {
                if (canvas != null) {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
        }
    }
}

কার্যকলাপ:

public class SurfaceViewActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MySurfaceView(this));
    }
}

0
private fun rotateTheView(view: View?, startAngle: Float, endAngle: Float) {
    val rotate = ObjectAnimator.ofFloat(view, "rotation", startAngle, endAngle)
    //rotate.setRepeatCount(10);
    rotate.duration = 400
    rotate.start()
}

1
যদিও এই কোডটি প্রশ্নের সমাধান দিতে পারে, কেন / কীভাবে এটি কাজ করে তা প্রসঙ্গে যুক্ত করা ভাল। এটি ভবিষ্যতের ব্যবহারকারীদের শিখতে এবং তাদের নিজস্ব কোডটিতে এই জ্ঞানটি প্রয়োগ করতে সহায়তা করতে পারে। কোডটি ব্যাখ্যা করা হলে আপনিও upvotes আকারে ব্যবহারকারীদের কাছ থেকে ইতিবাচক প্রতিক্রিয়া জানাতে পারেন।
borchvm
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.