旋转图片并添加动画效果

33

The two states of the image

我的现状

我有一个箭头图片(如左图)。当用户点击它时,它应该以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) {

            }
        });
    }

问题

我发现动画运行得很好,但是在设置图像时会有一点闪烁。可能是由于动画结束和图像设置之间的时间差异导致的。

我该如何解决这个闪烁问题?您有更好的方法来做到这一点吗?


以编程方式实现旋转动画。RotateAnimation:顺时针/逆时针 - Geet Thakur
9个回答

75

首先,你的最低SDK要求是多少?如果至少是Android 3.0,你可以使用更新的动画框架,并像这样使用动画来实现图像效果:

imageView.animate().rotation(180).start();
关于闪烁问题:在旋转后,我不会重置ImageView的源图像,而是保留原始图像,并确保旋转动画在完成后填充,使图像保持旋转状态。闪烁很可能是由于更改源图像时View的重新布局/重绘引起的。
进一步的视觉伪影(闪烁?)可能是由于原始旋转图像和旋转静态图像之间可能存在几个像素的差异所导致的。

2
ImageView在我按下它时只旋转一次。但是当我再次按下它时,它应该再次旋转,以此类推。但这并没有发生。有什么想法吗? - Aritra Roy
10
如果您正在使用我提供的代码示例,那么这段代码特别指定将视图“旋转至180度”。因此,如果它已经旋转到180度,则不会发生任何变化。在单击监听器中,您可以检查视图的当前旋转状态(.getRotation),如果不为0,则以类似的方式将其旋转回0。 - Zsombor Erdődy-Nagy
是的,我刚刚做到了,而且也成功了。现在,当旋转到0时,有没有一种控制动画方向的方法。我的意思是,它正在朝着特定的方向旋转,但我想朝相反的方向旋转。 - Aritra Roy
我猜你想要继续以相同的方向旋转视图,而不是顺时针旋转180度再逆时针旋转回0度。例如,您可以设置一个不断增加的旋转目标,即X * 180度,基于用户交互时视图的旋转情况(这可能会在动画进行中发生)。例如,在我们需要为视图上的点击旋转时:点击->旋转到180度->点击->旋转到2 x 180度->...你明白了。 - Zsombor Erdődy-Nagy
使用LinearInterpolator来实现完整的旋转。 - Andrew Glukhoff
1
Go: imageView.animate().rotation(0).rotation(180).start();Back: imageView.animate().rotation(180).rotation(0).start(); - Sam Chen

4
如果我是你,我会使用ViewPropertyAnimator(从API 12开始可用)。在我看来,它的语法更加直观易懂。
使用方法如下:
toggle.animate().rotation(0.5f);

同前一个答案一样。但是我如何确保每次按下图像时都发生旋转?现在它只会发生一次。 - Aritra Roy
7
使用“rotateBy”函数。请查看API文档,它将成为您新的最喜爱的动画工具。 - Alex.F
谢谢。我有没有办法控制旋转方向? - Aritra Roy
1
我会尝试一个负数值。但我不确定。 - Alex.F

2

如果您想保留动画的状态,可以使用setFillAfter


2
没有任何解释,也没有任何上下文。 - Maxime Claude

2

为什么不使用RotateAnimation?

在res目录下创建一个名为anim的文件夹,并在其中创建一个名为rotator.xml的文件。

<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图像添加到drawable文件夹中。然后打开res/main.xml,在布局中删除默认的textView,添加一个ImageView和Button。将ImageView的src属性设置为添加的图片的文件名,例如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);
            }
        });
    }
}

2

验证代码:(您可以按照我的解决方案进行操作)

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

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

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

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

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

1

KOTLIN

使用Kotlin,可以实现非常高效和流畅的ImageView旋转动画。

旋转动画之后,ImageView将被保留,无需动画监听器。

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

1
如果您想将图像顺时针旋转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()

请注意,如果您频繁旋转图像很多次,它不会停止在0-180-360的位置。因为如果您在前一个动画完成之前开始新动画,它会改变角度。
因此,更好的方法在已接受的答案中提供。它不依赖于当前动画状态。
private var angle = 0f

angle += 180f
view.animate().setDuration(300).rotation(angle).start()

0

KOTLIN:

使用仅一个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}
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接