Повернуть изображение с анимацией

Два состояния изображения

Что я имею

У меня есть изображение стрелки (как на левом). Когда пользователь нажимает на него, он должен поворачиваться на 180 градусов с анимацией и должен выглядеть как правильный.

Что я сделал

private void rotate(float degree, final int toggleV) {

        final RotateAnimation rotateAnim = new RotateAnimation(0.0f, degree,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);

        rotateAnim.setDuration(500);
        toggle.startAnimation(rotateAnim);
        rotateAnim.setAnimationListener(new Animation.AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {


                if (toggleV == 1)
                    toggle.setImageResource(R.drawable.toggle_up);
                else
                    toggle.setImageResource(R.drawable.toggle_down);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
    }

Эта проблема

Я вижу, что анимация работает нормально, но при настройке изображения наблюдается небольшое мерцание. Может быть из-за разницы во времени, когда анимация заканчивается и изображение установлено.

Как я могу удалить эту проблему мерцания? Есть ли у вас лучший подход для этого?

9 ответов

Решение

Прежде всего, какое минимальное требование к SDK? В случае, если это хотя бы Android 3.0, вы можете использовать более новую инфраструктуру анимации и анимировать свое изображение примерно так:

imageView.animate().rotation(180).start();

О мерцании: я бы не стал сбрасывать исходное изображение ImageView после поворота, я бы просто оставил в оригинале и убедился, что анимация поворота заполняется после анимации, оставляя изображение повернутым. Мерцание, скорее всего, вызвано ретрансляцией / перерисовкой View при смене исходного изображения.

Дополнительные визуальные артефакты (мерцание?) Могут быть вызваны тем, что исходное повернутое изображение и повернутое статическое изображение могут отличаться на несколько пикселей.

На вашем месте я бы использовал ViewPropertyAnimator (доступно из API 12). Его синтаксис более понятен IMO.
Использование будет:

toggle.animate().rotation(0.5f);

Проверенный код: (Вы можете следовать моему решению)

imageView.setImageResource(R.drawable.ic_arrow_up);

boolean up = true;

if (!up) { 
    up = true; 
    imageView.startAnimation(animate(up)); 
} else { 
    up = false; 
    imageView.startAnimation(animate(up)); 
}

private Animation animate(boolean up) {
    Animation anim = AnimationUtils.loadAnimation(this, up ? R.anim.rotate_up : R.anim.rotate_down);
    anim.setInterpolator(new LinearInterpolator()); // for smooth animation
    return anim;
}

рисуем /ic_arrow_up.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:fillColor="#3d3d3d"
        android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z"/>
</vector>

аним /rotate_up.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:fillEnabled="true">
    <rotate
        android:duration="200"
        android:fromDegrees="-180"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="0" />
</set>

аним /rotate_down.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:fillEnabled="true">
    <rotate
        android:duration="200"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="180" />
</set>

Я использовал этот код. Потому что это сохранит состояние анимации:

android:fillAfter="true"
android:fillEnabled="true"

Ты можешь использовать setFillAfter если вы хотите сохранить состояние вашей анимации.

      img_view.animate().rotation(360.0f).setDuration(1000);

Почему вы не используете RotateAnimation?

создайте папку с именем anim в res и файл с именем rotator.xml внутри res/anim.

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="400"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360"/>

Здесь один полный оборот будет завершен за 4000 мс (4 секунды). Теперь добавьте изображение PNG, которое вы хотите повернуть, в свою папку для рисования. Затем откройте res / main.xml, после удаления стандартного textView в макете, добавьте ImageView и Button в макет. Установите свойство src ImageView в качестве имени файла добавляемого изображения, например, android:src=”@drawable/myimg” Хорошо, давайте отредактируем основной класс. В onClick() для кнопки добавьте необходимый код для запуска анимации. Проверьте следующий код.

public class AnimationActivity extends Activity {

    public ImageView  myImage ;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        myImage = (ImageView)findViewById(R.id.imageView1);
        final Animation myRotation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.rotator);
        ((Button)findViewById(R.id.button1)).setOnClickListener(new OnClickListener()    {
            @Override
            public void onClick(View arg0) {
                myImage.startAnimation(myRotation);
            }
        });
    }
}

КОТЛИН

очень эффективная и плавная анимация вращения ImageView в Kotlin.

После анимации вращения ImageView сохраняется без прослушивателя анимации.

      imageView.animate().rotation(angle).setDuration(700).setInterpolator(AccelerateDecelerateInterpolator()).start()

Если вы хотите повернуть изображение на 180 градусов по часовой стрелке.

private var isExpanded = true

private fun rotateImage(view: View) {
    val startAngle = if (isExpanded) 0f else 180f
    ObjectAnimator.ofFloat(view, View.ROTATION, startAngle, startAngle + 180f).apply {
        duration = 300
        interpolator = LinearInterpolator()
        start()
    }
    isExpanded = !isExpanded
}

Или проще (как писал @Alex.F):

view.animate().setDuration(300).rotationBy(180f).start()

КОТЛИН:

Плавный способ сделать анимацию расширения и свертывания с помощью только одного ImageView:

      class MainActivity : AppCompatActivity() {

    var isExpanded = true

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)


        val imageView = findViewById<ImageView>(R.id.image_header_toggle)

        imageView.setOnClickListener {
            if (!isExpanded) {
                imageView.animate().apply {
                duration = 500
                rotation(180f)
                isExpanded = true}
            }else{
                imageView.animate().apply {
                duration = 500
                rotation(0f)
                isExpanded = false}
            }
        }
    }
}
Другие вопросы по тегам