是否可以创建具有某种动画的drawable,无论是逐帧动画,旋转等,都被定义为xml drawable并且可以由单个Drawable对象表示而无需处理用代码中的动画?
我想如何使用它: 我有一个列表,此列表中的每个项目可能在某个时候发生了一些事情。虽然它正在发生,但我希望有一个类似于不确定的ProgressBar的旋转进度动画。由于屏幕上可能还有其中的几个,我认为如果它们共享相同的Drawable,它们只需要在内存中有一个实例,它们的动画会被同步,所以你不会在各个点上有一堆旋转对象在旋转动画中。
我不喜欢这种方法。我只是想想一种最有效的方式来显示几个旋转进度动画,理想情况下将它们同步在一起,使它们在外观上保持一致。
由于
回应Sybiam的回答:
我尝试过实现RotateDrawable,但它没有旋转。
到目前为止,这是我的xml for the drawable:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/my_drawable_to_rotate"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="800"
android:visible="true" />
我尝试使用drawable作为ImageView的src和背景,并且两种方式都只产生非旋转图像。
是否有必须开始图像旋转的东西?
答案 0 :(得分:16)
是的!我通过阅读ProgressBar
代码发现的(未记录的)密钥是您必须在Drawable.setLevel()
中调用onDraw()
才能使<rotate>
内容生效。 ProgressBar
的工作方式与此类似(省略了额外的不重要代码):
可绘制的XML:
<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>
在onDraw()
:
Drawable d = getDrawable();
if (d != null)
{
// Translate canvas so a indeterminate circular progress bar with
// padding rotates properly in its animation
canvas.save();
canvas.translate(getPaddingLeft(), getPaddingTop());
long time = getDrawingTime();
// I'm not sure about the +1.
float prog = (float)(time % ANIM_PERIOD+1) / (float)ANIM_PERIOD;
int level = (int)(MAX_LEVEL * prog);
d.setLevel(level);
d.draw(canvas);
canvas.restore();
ViewCompat.postInvalidateOnAnimation(this);
}
MAX_LEVEL
是常量,总是10000(根据文档)。
ANIM_PERIOD
是动画的句点,以毫秒为单位。
很遗憾,因为您需要修改onDraw()
,所以不能将此drawable放在ImageView
中,因为ImageView
永远不会更改可绘制级别。但是,您可以从外部更改ImageView
的可绘制级别。 ProgressBar
(ab)使用AlphaAnimation
来设置关卡。所以你会做这样的事情:
mMyImageView.setImageDrawable(myDrawable);
ObjectAnimator anim = ObjectAnimator.ofInt(myDrawable, "level", 0, MAX_LEVEL);
anim.setRepeatCount(ObjectAnimator.INFINITE);
anim.start();
它可能有效,但我没有测试过。
实际上有一个ImageView.setImageLevel()
方法,因此它可能很简单:
ObjectAnimator anim = ObjectAnimator.ofInt(myImageVew, "ImageLevel", 0, MAX_LEVEL);
anim.setRepeatCount(ObjectAnimator.INFINITE);
anim.start();
答案 1 :(得分:7)
编辑: 这是我在这里找到的答案。 Drawable Rotating around its center Android
编辑2: 你是对的,RotateDrawable好像坏了。我不知道我也试过了。我还没有成功使它成为动画。但我确实成功地轮换了它。你必须使用setLevel来旋转它。虽然看起来不太有用。我浏览了代码并且RotateDrawable甚至没有夸大动画持续时间,当前旋转似乎奇怪地使用关卡作为旋转度量。我相信你必须将它与AnimationDrawable一起使用,但在这里再次使用它。它只是为我坠毁。我还没有使用过这个功能,但计划将来使用它。我浏览了网页,RotateDrawable似乎与几乎每个Drawable对象都没有文档。
答案 2 :(得分:2)
这是一种可能的方法(特别是当你有一个Drawable设置并需要为它设置动画时)。我们的想法是包装drawable并用动画装饰它。在我的情况下,我不得不旋转它,所以下面你可以找到示例实现:
public class RotatableDrawable extends DrawableWrapper {
private float rotation;
private Rect bounds;
private ObjectAnimator animator;
private long defaultAnimationDuration;
public RotatableDrawable(Resources resources, Drawable drawable) {
super(vectorToBitmapDrawableIfNeeded(resources, drawable));
bounds = new Rect();
defaultAnimationDuration = resources.getInteger(android.R.integer.config_mediumAnimTime);
}
@Override
public void draw(Canvas canvas) {
copyBounds(bounds);
canvas.save();
canvas.rotate(rotation, bounds.centerX(), bounds.centerY());
super.draw(canvas);
canvas.restore();
}
public void rotate(float degrees) {
rotate(degrees, defaultAnimationDuration);
}
public void rotate(float degrees, long millis) {
if (null != animator && animator.isStarted()) {
animator.end();
} else if (null == animator) {
animator = ObjectAnimator.ofFloat(this, "rotation", 0, 0);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
}
animator.setFloatValues(rotation, degrees);
animator.setDuration(millis).start();
}
@AnimatorSetter
public void setRotation(float degrees) {
this.rotation = degrees % 360;
invalidateSelf();
}
/**
* Workaround for issues related to vector drawables rotation and scaling:
* https://code.google.com/p/android/issues/detail?id=192413
* https://code.google.com/p/android/issues/detail?id=208453
*/
private static Drawable vectorToBitmapDrawableIfNeeded(Resources resources, Drawable drawable) {
if (drawable instanceof VectorDrawable) {
Bitmap b = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
drawable.setBounds(0, 0, c.getWidth(), c.getHeight());
drawable.draw(c);
drawable = new BitmapDrawable(resources, b);
}
return drawable;
}
}
你可以像这样使用它(旋转工具栏导航图标360度):
backIcon = new RotatableDrawable(getResources(), toolbar.getNavigationIcon().mutate());
toolbar.setNavigationIcon(backIcon);
backIcon.rotate(360);
添加一种无限期旋转的方法(setRepeatMode INFINITE for animator
)
答案 3 :(得分:1)
您可以从学习API Demos项目的ProgressBar2开始(它可以作为SDK的一部分使用)。特别要注意R.layout.progressbar_2
。
答案 4 :(得分:0)
private ValueAnimator rotateDrawable(RotateDrawable drawable, int fromDegree, int toDegree) {
drawable.setFromDegrees(fromDegree);
drawable.setToDegrees(toDegree);
return ObjectAnimator.ofInt(drawable, "level", 0, 10000);
}
level是从0到100000的interpulting值。实际动画值由setter方法设置
答案 5 :(得分:0)
你可以使用stateListAnimator
<ImageView
android:id="@+id/your_id"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/your_drawable"
android:stateListAnimator="@anim/bounce" />
和反弹
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/bounce">
<translate
android:duration="900"
android:fromXDelta="100%p"
android:toXDelta="0%p" />
</set>
答案 6 :(得分:0)
我将这篇帖子重新生动起来,只是将我的解决方案与可绘制的矢量一起发布:
因此,您需要在可绘制资源(@ drawable / ic_brush_24dp)中绘制1个矢量:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<group
android:name="rotation" <---- target name of animated-vector
android:pivotX="12.0"
android:pivotY="12.0"
android:rotation="0.0"> <--- propertyName of animator
<path
android:fillColor="#FF000000"
android:pathData="M7,14c-1.66,0 -3,1.34 -3,3 0,1.31 -1.16,2 -2,2 0.92,1.22 2.49,2 4,2 2.21,0 4,-1.79 4,-4 0,-1.66 -1.34,-3 -3,-3zM20.71,4.63l-1.34,-1.34c-0.39,-0.39 -1.02,-0.39 -1.41,0L9,12.25 11.75,15l8.96,-8.96c0.39,-0.39 0.39,-1.02 0,-1.41z" />
</group>
</vector>
然后,您需要在动画器资源文件夹(@ animator / pendulum)中使用动画器
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="350"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:propertyName="rotation"
android:valueFrom="0.0"
android:valueTo="-90.0" />
</set>
然后,您需要在可绘制资源(@ drawable / test_anim_brush2)中使用动画矢量:
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_brush_24dp">
<target
android:name="rotation"
android:animation="@animator/pendulum" />
</animated-vector>
然后您需要扩展ImageView(因为这是我发现开始动画的唯一方法)
public class ImageView extends AppCompatImageView{
public ImageView(Context context){
super(context);
init(context, null, 0);
}
public ImageView(Context context, AttributeSet attrs){
super(context, attrs);
init(context, attrs, 0);
}
public ImageView(Context context, AttributeSet attrs, int defStyleAttr){
super(context, attrs, defStyleAttr);
init(context, attrs, 0);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr){
}
@Override
protected void onAttachedToWindow(){
super.onAttachedToWindow();
Drawable d = getBackground();
if(d instanceof AnimatedVectorDrawable){
AnimatedVectorDrawable anim = (AnimatedVectorDrawable)d;
anim.start();
}
}
@Override
protected void onDetachedFromWindow(){
super.onDetachedFromWindow();
Drawable d = getBackground();
if(d instanceof AnimatedVectorDrawable){
AnimatedVectorDrawable anim = (AnimatedVectorDrawable)d;
anim.stop();
}
}
}
然后将您的imageView添加到布局中:
<ui.component.ImageView
android:id="@+id/test_anim_brush"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:background="@drawable/test_anim_brush2"/>
专业版:
骗局