如何使用“RotateDrawable”?

20

有人能告诉我如何让 RotateDrawable 工作,无论是通过代码还是XML?动画绘图的文档非常不完善,似乎只对图像有效。我想要能够动画化所有可绘制对象。当我尝试从XML中获取一个 RotateDrawble 时,它会导致异常。从XML找到 RotateDrawable 的正确函数是什么?


https://dev59.com/KG445IYBdhLWcg3wpL1_ - baboo
我不明白你的问题。你是想要一个动画,还是仅仅旋转图像?如果是旋转的话,请查看这个帖子:https://dev59.com/x2025IYBdhLWcg3wqX1o#21376008 - android developer
10个回答

19

这里有一个不错的解决方案,可以为imageView添加一个旋转的drawable:

Drawable getRotateDrawable(final Bitmap b, final float angle) {
    final BitmapDrawable drawable = new BitmapDrawable(getResources(), b) {
        @Override
        public void draw(final Canvas canvas) {
            canvas.save();
            canvas.rotate(angle, b.getWidth() / 2, b.getHeight() / 2);
            super.draw(canvas);
            canvas.restore();
        }
    };
    return drawable;
}

使用方法:

Bitmap b=...
float angle=...
final Drawable rotatedDrawable = getRotateDrawable(b,angle);
root.setImageDrawable(rotatedDrawable);

另一个选择:

private Drawable getRotateDrawable(final Drawable d, final float angle) {
    final Drawable[] arD = { d };
    return new LayerDrawable(arD) {
        @Override
        public void draw(final Canvas canvas) {
            canvas.save();
            canvas.rotate(angle, d.getBounds().width() / 2, d.getBounds().height() / 2);
            super.draw(canvas);
            canvas.restore();
        }
    };
}

此外,如果你希望旋转位图,但担心OOM,可以使用我制作的一个NDK解决方案这里


12

您需要为“level”属性创建动画,其中0是起始值,10000是结束值。

以下示例从开头到结尾进行动画处理,您可以使用此方法轻松地反转动画。

final RotateDrawable rotateDrawable = ...
ObjectAnimator.ofInt(rotateDrawable, "level", 0, 10000).start();

1
一年多后,这些信息现在可以在此处找到:https://developer.android.com/reference/android/graphics/drawable/Drawable.html#setLevel(int) - bogl

7
我想添加一个完整的示例来对ImageView上的进度图标进行动画处理,它基于Mark Hetherington的答案。
因此,我的动画如下:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
                 android:pivotX="50%"
                 android:pivotY="50%"
                 android:fromDegrees="0"
                 android:toDegrees="-360"
                 android:duration="100"
                 android:drawable="@drawable/ic_loop_black_24dp"
    />

图标来自https://material.io/icons/

然后我的布局包含一个ImageView,如下所示:

        <ImageView
            android:id="@+id/progress"
            android:layout_marginTop="0dp"
            android:layout_marginLeft="-3dp"
            android:layout_width="30dp"
            android:layout_height="30dp"

            android:visibility="gone"
            android:scaleType="fitCenter"
            android:background="@drawable/progress_anim"
            android:layout_gravity="center_horizontal|center_vertical"
            />

最后,在代码中,当我需要显示动画时,我会这样做:
    RotateDrawable rotateDrawable = ((RotateDrawable)progressImage.getBackground());
    ObjectAnimator anim = ObjectAnimator.ofInt(rotateDrawable, "level", 0, 10000);
    anim.setDuration(1000);
    anim.setRepeatCount(ValueAnimator.INFINITE);
    anim.start();

4

RotateDrawable似乎不能进行动画。相反,您需要使用setLevel来改变可绘制对象的旋转。

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/your_drawable"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="360" />

设置级别将旋转可绘制对象:

final ImageView image = (ImageView)findViewById(R.id.imageView1);
final RotateDrawable drawable = (RotateDrawable)image.getDrawable();
drawable.setLevel(500);

我肯定还是漏了点什么。 首先,您正在使用 <rotate> 标签做什么?您没有在任何地方进行膨胀。其次,我尝试将 Drawable 强制转换为 RotateDrawable,并得到以下强制转换异常 java.lang.ClassCastException: android.graphics.drawable.BitmapDrawable - Frank Sposaro
我猜我的示例假设有一个布局,并且该布局使用带有RotateDrawable的ImageView。如果您有一个位图,则RotateDrawable引用它而不是布局。 - Carson Reinke
2
你如何设置动画的速度?我尝试了各种不同的“持续时间”值,但似乎没有任何效果... - android developer

3
以下代码返回一个Drawable包装器,可以通过程序将另一个Drawable进行旋转:
Drawable rotateDrawable(Drawable d, final float angle) {
    // Use LayerDrawable, because it's simpler than RotateDrawable.
    Drawable[] arD = {
        d
    };
    return new LayerDrawable(arD) {
        @Override
        public void draw(Canvas canvas) {
            canvas.save();
            canvas.rotate(angle);
            super.draw(canvas);
            canvas.restore();
        }
    };
}

你忘记在rotate()函数中设置枢轴了。这里有一个更好的解决方案:https://dev59.com/x2025IYBdhLWcg3wqX1o#21376008 - android developer

2

这是一个很好的工作示例。参数“duration”用于对其进行动画处理。

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="4000"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="720" >

    <shape
        android:innerRadius="20dp"
        android:shape="ring"
        android:thickness="4dp"
        android:useLevel="false" >
        <size
            android:height="48dp"
            android:width="48dp" />

        <gradient
            android:centerY="0.5"
            android:endColor="@android:color/white"
            android:startColor="#00ffffff"
            android:type="sweep"
            android:useLevel="false" />
    </shape>

</rotate>

2

我没有使用过RotateDrawable,但如果你只是想在图形上实现旋转动画,那么你不需要它。具有“级别”(level)的可绘制对象,如RotateDrawable,旨在传达信息而不是为了动画视图。

以下代码可以使ImageView围绕其中心旋转:

ImageView myImageView = (ImageView)findViewById(R.id.my_imageview);

AnimationSet animSet = new AnimationSet(true);
animSet.setInterpolator(new DecelerateInterpolator());
animSet.setFillAfter(true);
animSet.setFillEnabled(true);

final RotateAnimation animRotate = new RotateAnimation(0.0f, -90.0f,
    RotateAnimation.RELATIVE_TO_SELF, 0.5f, 
    RotateAnimation.RELATIVE_TO_SELF, 0.5f);

animRotate.setDuration(1500);
animRotate.setFillAfter(true);
animSet.addAnimation(animRotate);

myImageView.startAnimation(animSet);

3
感谢您的回复,David。如果我正确理解了您的方法,那么这将旋转整个视图,而我最终想要的是能够旋转/动画显示单个Drawable,例如指针在固定背景上旋转,因为它是刻度盘的标度。这就是为什么我试图使用RotateDrawable,但不幸的是无法理解文档! - D-Dᴙum

2

既然你正在尝试使用Almero的Android手势检测器,我决定做同样的事情以找到一个合适的解决方案:

public class MainActivity extends Activity {

    private RotateGestureDetector mRotateDetector;
    private float mRotationDegrees = 0.f;
    private static final float ROTATION_RATIO = 2;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRotateDetector = new RotateGestureDetector(getApplicationContext(), new RotateListener());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mRotateDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }

    private class RotateListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
        @Override
        public boolean onRotate(RotateGestureDetector detector) {
            mRotationDegrees -= detector.getRotationDegreesDelta();
            ImageView v = (ImageView) findViewById(R.id.imageView);
            // For NineOldAndroids library only!
            ViewHelper.setRotation(v, mRotationDegrees * ROTATION_RATIO);
            // For HONEYCOMB and later only!
            v.setRotation(mRotationDegrees * ROTATION_RATIO);
            return true;
        }
    }
}

这对我来说很好用(我可以使用双指旋转手势旋转ImageView。 注意:不要忘记选择适当的旋转方法调用。我已经将它们都注释了以引起您的注意。 ROTATION_RATIO只是一个乘数,可以加速我的手指移动的旋转响应。 您可以为View使用任何旋转轴(setRotation()、setRotationX()和setRotationY()方法)。 为了在API级别低于11(Honeycomb之前的设备)的Android设备上支持此代码,您可能需要使用NineOldAndroid库。

2

你可以手动调用 RotatedDrawable.setLevel() 来旋转 Drawable,或者你可以查看 ProgressBar 的代码,不确定状态的 drawable 是一个 LayerDrawable,它的子项是 RotatedDrawable,像这样:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <rotate
             android:drawable="@drawable/spinner_48_outer_holo"
             android:pivotX="50%"
             android:pivotY="50%"
             android:fromDegrees="0"
             android:toDegrees="1080" />
    </item>
    <item>
        <rotate
             android:drawable="@drawable/spinner_48_inner_holo"
             android:pivotX="50%"
             android:pivotY="50%"
             android:fromDegrees="720"
             android:toDegrees="0" />
    </item>
</layer-list>

旋转动画是由ProgressBar的onDraw方法驱动的。

0
如果您想永久旋转可绘制对象,可以在可绘制的 xml 中使用 animated-rotate 标签如下所示。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <animated-rotate android:drawable="@drawable/ic_refresh" android:pivotX="50%" android:pivotY="50%" />
    </item>
</selector>

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