एंड्रॉइड में एक चिकनी छवि रोटेशन कैसे करें?


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

आप AccelerateInterpolator के बारे में सही हैं; आपको इसके बजाय LinearInterpolator का उपयोग करना चाहिए।

आप 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" />

और अपने एनीमेशन XML में जोड़ें:

android:interpolator="@anim/linear_interpolator"

विशेष नोट: यदि आपका रोटेट एनीमेशन सेट के अंदर है, तो इंटरपोलर को सेट करना काम नहीं लगता है। बारी बारी से बनाने से शीर्ष तत्व इसे ठीक करता है। (इससे आपका समय बचेगा।)


1
ऐसा इसलिए है क्योंकि इंटरपोलर को गलत (कोई "एन") नहीं लिखा गया था। आपको अपना खुद का बनाने की ज़रूरत नहीं है
किंगपिन

25
मैंने हर इंटरपोलर को उपलब्ध करने की कोशिश की है, जिसमें रैखिक भी शामिल है, और मुझे अभी भी हर चक्र की शुरुआत में यह "छोटी" अड़चन मिलती है।
एडम रबंग

11
यदि आपका रोटेट एनिमेशन किसी सेट के अंदर है, तो इंटरपोलर सेट करना काम नहीं करता है। रोटेट करने से शीर्ष तत्व ठीक हो जाता है
शालिफे

अरे, क्या होगा यदि आप वास्तव में हर एनिमेशन के बीच छोटे "ठहराव" के बिना acceler_decelerate_interpolator का उपयोग करना चाहते हैं?
एगोनिस्ट_

90

मुझे भी यह समस्या थी, और सफलता के बिना xml में रैखिक प्रक्षेपक सेट करने का प्रयास किया। मेरे लिए काम करने वाला समाधान एनीमेशन को कोड में RotateAnimation के रूप में बनाना था।

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);
Fonix

4
यदि आप चाहते हैं कि एनीमेशन स्थायी रूप से बिना किसी अंत के साथ रहे, तो जोड़ लेंrotate.setRepeatCount(Animation.INFINITE);
ahmednabil88

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 है और एंड्रॉइड सेट करें: रिपीटमोड = "रिवर्स" - दो अलग-अलग XML फाइलें होने की कोई आवश्यकता नहीं है।
राउंडस्पारो हिल्टैक्स

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)...

सही काम कर रहा है, क्या imageView.clearAnimation () रननेबल को भी साफ करेगा?
8

स्टार्टिंग एनिमेशन के लिए इसका काम ठीक है, लेकिन रनवेनेबल के बाद इसकी इमेज क्लीनव्यू से साफ नहीं होती है। क्लियरएनिमेशन (), मैं टच श्रोता ईवेंट में इस्तेमाल करता हूं
अभिजीत जगताप

स्वतंत्र रूप से इन रनवे को रोक नहीं सकते
पैंट

@ आप कुछ शर्त पर (इस) के साथ कॉल कर सकते हैं। यदि स्थिति गलत है, तो WithAndAction (यह) कॉल नहीं किया जाएगा, और एनीमेशन को रोकना चाहिए
विटाली ज़िनचेंको



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();
    } 

दृश्य आपके ImageView या अन्य विजेट का उद्देश्य है।

rotate.setRepeatCount (10); अपने रोटेशन को दोहराने के लिए उपयोग करें।

500 आपकी एनीमेशन समय अवधि है।


6

प्रुनिंग <set> -Element कि लिपटे<rotate> तत्व हल समस्या!

शलाफी को धन्यवाद!

तो आपका Rotation_ccw.xml इस तरह से ढीला होना चाहिए:

<?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);
        }

आप "एनीमेशन" चर घोषणा कहां कर रहे हैं
ऋषभ सक्सेना

3

जैसा कि पिछलग्गू ने उल्लेख किया है कि लाइनर iterpolator ठीक है। लेकिन अगर रोटेशन एक सेट के अंदर हो तो आपको इसे सुचारू बनाने के लिए android: shareInterpolator = "false" डालना होगा।

<?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 डिग्री को कम करने की कोशिश की और व्यवहार में कोई परिवर्तन नहीं हुआ।
एमएमबी

1

पुनरारंभ करने से बचने के लिए 360 से अधिक का उपयोग करने का प्रयास करें।

मैं ३६०० का उपयोग करता हूं और यह मेरे लिए ठीक काम करता है:

<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 पर ले जाना चाहते हैं, तो एनीमेशन एपीआई इंटरमीडिएट लोकेशन (ट्वॉयइंग) से बाहर निकलता है और फिर मुख्य थ्रेड पर कतारें एक टाइमर का उपयोग करके उचित समय पर उचित मूव ऑपरेशन करता है। । यह ठीक काम करता है सिवाय इसके कि मुख्य धागा आमतौर पर कई अन्य चीजों के लिए उपयोग किया जाता है - पेंटिंग, फाइलें खोलना, उपयोगकर्ता इनपुट का जवाब देना आदि। एक कतारबद्ध टाइमर को अक्सर देरी हो सकती है। अच्छी तरह से लिखित कार्यक्रम हमेशा पृष्ठभूमि (गैर मुख्य) थ्रेड्स में अधिक से अधिक संचालन करने की कोशिश करेंगे, हालांकि आप हमेशा मुख्य धागे का उपयोग करने से बच नहीं सकते हैं। ऑपरेशन जिन्हें आपको UI ऑब्जेक्ट पर संचालित करने की आवश्यकता होती है, उन्हें हमेशा मुख्य थ्रेड पर किया जाना चाहिए। इसके अलावा, कई एपीआई थ्रेड-सेफ्टी के रूप में मुख्य थ्रेड पर वापस ऑपरेशन करेंगे।

दृश्य सभी एक ही जीयूआई धागे पर खींचे जाते हैं जो सभी उपयोगकर्ता इंटरैक्शन के लिए भी उपयोग किया जाता है।

इसलिए यदि आपको GUI को तेजी से अपडेट करने की आवश्यकता है या यदि रेंडरिंग में बहुत अधिक समय लगता है और उपयोगकर्ता अनुभव को प्रभावित करता है, तो SurfaceView का उपयोग करें।

रोटेशन छवि का उदाहरण:

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 के रूप में सकारात्मक प्रतिक्रिया मिलने की संभावना होती है।
बोरवम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.