Как сделать плавный поворот изображения в Android? - PullRequest
195 голосов
/ 28 октября 2009

Я использую 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), но я не знаю, как сказать ему не интерполировать анимацию.

Как я могу отключить интерполяцию (если это действительно проблема), чтобы сделать цикл анимации плавным?

Ответы [ 15 ]

189 голосов
/ 28 октября 2009

Вы правы насчет 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"

Специальное примечание: Если анимация поворота находится внутри набора, настройка интерполятора не работает. Поворот верхнего элемента исправляет это. (это сэкономит ваше время.)

71 голосов
/ 07 мая 2015

У меня тоже была эта проблема, и я безуспешно пытался установить линейный интерполятор в 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);
32 голосов
/ 26 апреля 2013

отлично работает

<?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" />
30 голосов
/ 07 октября 2015

Может быть, что-то вроде этого поможет:

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)...
28 голосов
/ 17 марта 2011

Попробуйте использовать toDegrees="359", поскольку 360 ° и 0 ° одинаковы.

6 голосов
/ 26 июня 2013

Обрезка <set> -элемента, обернутого <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"
    />
5 голосов
/ 24 августа 2017
ObjectAnimator.ofFloat(view, View.ROTATION, 0f, 360f).setDuration(300).start();

Попробуйте это.

3 голосов
/ 25 октября 2018

Объект поворота программно.

// вращение по часовой стрелке:

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

view - это объект вашего ImageView или других виджетов.

rotate.setRepeatCount (10); используется для повторения вашего вращения.

500 - ваша продолжительность анимации.

3 голосов
/ 13 января 2015

Как уже упоминал Ханри, положить лайнер итерполятор можно. Но если вращение находится внутри набора, вы должны поставить 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 не равен false, приведенный выше код дает сбои.

3 голосов
/ 25 августа 2012

Независимо от того, что я пытался, я не мог заставить это работать правильно, используя код (и 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);
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...