سؤال

أنا أستخدم أ RotateAnimation لتدوير صورة أستخدمها كأداة تدوير دورية مخصصة في Android.هنا بلدي 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)، لكنني لا أعرف كيف أخبرها بعدم استيفاء الرسوم المتحركة.

كيف يمكنني إيقاف الاستيفاء (إذا كانت هذه هي المشكلة بالفعل) لجعل دورة الرسوم المتحركة الخاصة بي سلسة؟

هل كانت مفيدة؟

المحلول

وأنت على حق حول AccelerateInterpolator. يجب عليك استخدام LinearInterpolator بدلا من ذلك.

ويمكنك استخدام android.R.anim.linear_interpolator المدمج في ملف XML من الرسوم المتحركة الخاصة بك مع android:interpolator="@android:anim/linear_interpolator".

وأو يمكنك إنشاء الخاصة ملف الاستيفاء XML الخاصة بك في المشروع، على سبيل المثال تسميته 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"

<قوية> ملاحظة خاصة: إذا لديك الرسوم المتحركة تدوير هو داخل مجموعة، وتحديد interpolator لا يبدو أن العمل. جعل تدوير العنصر كبار يصلح له. (وهذا سيوفر وقتك.)

نصائح أخرى

وكان لي هذه المشكلة أيضا، وحاول لضبط interpolator الخطي في أكس دون نجاح. وكان الحل الذي عملت بالنسبة لي لإنشاء الرسوم المتحركة باعتبارها 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);

وهذا يعمل بشكل جيد

<?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" />

وربما شيء من هذا القبيل سيساعد:

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

وحاول استخدام toDegrees="359" منذ 360 درجة و 0 درجة هي نفسها.

وتشذيب <set>-العنصر الذي لف <rotate>-العنصر يحل المشكلة!

وبفضل الشلفي!

وهكذا Rotation_ccw.xml الخاصة بك ينبغي أن loook مثل هذا:

<?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"
    />
ObjectAnimator.ofFloat(view, View.ROTATION, 0f, 360f).setDuration(300).start();

وجرب هذا.

وبغض النظر عن ما حاولت، لم أتمكن من الحصول على هذا الحق في العمل باستخدام رمز (وsetRotation) لسلسة دوران الرسوم المتحركة. ما انتهى به كان إجراء التغييرات درجة صغيرة جدا، أن توقف الصغيرة هي غير ملحوظ. إذا كنت لا تحتاج إلى القيام به العديد من الدورات، ووقت لتنفيذ هذه الحلقة لا يكاد يذكر. تأثير هو تناوب على نحو سلس:

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

وكما ذكر أعلاه hanry وضع بطانة iterpolator على ما يرام. ولكن إذا تناوب هو داخل مجموعة يجب وضع الروبوت: 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 كونها ليست كاذبة، رمز أعلاه يعطي مواطن الخلل.

تدوير الكائن برمجياً.

// دوران عقارب الساعة :

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

// الدوران عكس اتجاه عقارب الساعة:

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

منظر هو كائن ImageView الخاص بك أو الحاجيات الأخرى.

Rotate.setRepeatCount(10); استخدامها لتكرار التناوب الخاص بك.

500 هي المدة الزمنية للرسوم المتحركة الخاصة بك.

إذا كنت تستخدم الرسوم المتحركة مجموعة مثلي يجب أن تضيف الاستيفاء داخل علامة مجموعة:

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

وهذا عمل بالنسبة لي.

هل من الممكن أن تذهب ل0-360، كنت تنفق أكثر من ذلك بقليل الوقت قليلا في 0/360 من كنت تتوقع؟ ربما وضع toDegrees إلى 359 أو 358.

في الروبوت، إذا كنت ترغب في تحريك كائن وجعلها نقل كائن من LOCATION1 إلى LOCATION2، فإن الأرقام الرسوم المتحركة API من المواقع المتوسطة (tweening ومن) ثم قوائم الانتظار على موضوع الرئيسي للعمليات نقل المناسبة في الأوقات المناسبة باستخدام جهاز توقيت. هذا يعمل بشكل جيد إلا أنه يتم استخدام موضوع الرئيسي عادة لأشياء أخرى كثيرة - اللوحة، وفتح الملفات، والاستجابة لمدخلات المستخدم وما إلى ذلك توقيت وغالبا ما يتأخر في قائمة الانتظار. سوف البرامج المكتوبة بشكل جيد دائما في محاولة للقيام العديد من عمليات ممكن في الخلفية (غير الرئيسية) المواضيع لكن لا يمكنك دائما تجنب استخدام الخيط الرئيسي. العمليات التي تتطلب منك أن تعمل على كائن UI دائما إلى أن يتم ذلك على الترابط الرئيسي. أيضا، فإن العديد من واجهات برمجة التطبيقات بضخ عمليات العودة إلى موضوع الرئيسي كشكل من أشكال موضوع السلامة.

كلها مرسومة

وجهات النظر حول نفس موضوع واجهة المستخدم الرسومية التي تستخدم أيضا لجميع تفاعل المستخدم.

وحتى إذا كنت تحتاج إلى تحديث واجهة المستخدم الرسومية بسرعة أو إذا كان التقديم يأخذ الكثير من الوقت ويؤثر على تجربة المستخدم ثم استخدام 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));
    }
}

وحاول استخدام أكثر من 360 لتجنب إعادة تشغيل.

وأنا استخدم 3600 insted من 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%" />

في Kotlin:

 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)
        })
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top