Is it possible to have an animated drawing?

Is it possible to create a drawable that has some kind of animation, be it frame-by-frame animation, rotation, etc., which is defined as xml-drawable and can be represented by a single Drawable without having to deal with animation in the code?

As I think, to use it: I have a list, and each item in this list can someday do something with it. While this happens, I would like the tweened animation to rotate in the same way as the undefined ProgressBar. Since there may also be several such elements on the screen, I thought that if they all shared the same Drawable, they would only need one instance from it in memory, and their animation would be synchronized so that you did not have a bunch of rotating objects at different points in a rotating animation.

I am not attached to this approach. I'm just trying to think of the most efficient way to display multiple motion tween animations and ideally synchronize them so that they are consistent in appearance.

thanks

In response to Sybiam's answer:

I tried to implement RotateDrawable, but it does not rotate.

Here is my xml for drawing so far:

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

I tried using this drawing as src and background ImageView, and in both cases a non-rotating image was created.

Is there something that should start the rotation of the image?

+7
source share
6 answers

Yes! The key (undocumented) that I discovered while reading the ProgressBar code is that you have to call Drawable.setLevel() in onDraw() so that the <rotate> object has any effect. ProgressBar works something like this (superfluous non-essential code is omitted):

Selectable 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> 

In 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 is a constant and always 10000 (according to the docs). ANIM_PERIOD is the period of your animation in milliseconds.

Unfortunately, since you need to change onDraw() , you cannot just put this drawable into an ImageView , since ImageView never changes the allowable level. However, you can change the output level from outside the ImageView . ProgressBar (ab) uses AlphaAnimation to set the level. So you would do something like this:

 mMyImageView.setImageDrawable(myDrawable); ObjectAnimator anim = ObjectAnimator.ofInt(myDrawable, "level", 0, MAX_LEVEL); anim.setRepeatCount(ObjectAnimator.INFINITE); anim.start(); 

This might work, but I have not tested it.

Edit

In fact, there is an ImageView.setImageLevel() method, so it can be as simple as:

 ObjectAnimator anim = ObjectAnimator.ofInt(myImageVew, "ImageLevel", 0, MAX_LEVEL); anim.setRepeatCount(ObjectAnimator.INFINITE); anim.start(); 
+15
source

Drawables

Come here! And this one is for RotateDrawable . I believe that from the Dock it should be quite difficult. You can define everything in the xml file and set the background of the view as a drawn xml./drawable/myrotate.xml -> @ drawable / myrotate

Edit: This is the answer I found here. Drawable Rotates Around Its Android Center

Edit 2: You are right that RotateDrawable seems to be broken. I don’t know, I tried it too. I have not yet managed to make him alive. But I really tried to rotate it. You should use setLevel, which will rotate it. Although it is not very useful. I looked at the code, and RotateDrawable doesn't even inflate the duration of the animation, and the current rotation seems weird using a level as a measure for rotation. I believe you should use it with AnimationDrawable, but here again. He just crashed for me. I have not used this feature yet, but I planned to use it in the future. I was browsing the Internet and RotateDrawable seems very undocumented, like almost all Drawable objects.

+7
source

Here is one of the possible ways (especially useful when you have Drawable installed somewhere and need to revive it). The idea is to wrap the drawing and decorate it with animation. In my case, I had to rotate it, so below you can find an example implementation:

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

and you can use it like this (360 degree rotation in the navigation bar):

 backIcon = new RotatableDrawable(getResources(), toolbar.getNavigationIcon().mutate()); toolbar.setNavigationIcon(backIcon); backIcon.rotate(360); 

You should not add a method that will rotate it indefinitely ( setRepeatMode INFINITE for animator )

+2
source

You can start by exploring the ProgressBar2 Demos API project (available as part of the SDK). Pay particular attention to R.layout.progressbar_2 .

+1
source
 private ValueAnimator rotateDrawable(RotateDrawable drawable, int fromDegree, int toDegree) { drawable.setFromDegrees(fromDegree); drawable.setToDegrees(toDegree); return ObjectAnimator.ofInt(drawable, "level", 0, 10000); } 
Level

is an interpolation value from 0 to 100000. The actual animation values ​​are set using setter methods

0
source

you can use stateListAnimator

  <ImageView android:id="@+id/your_id" android:layout_width="200dp" android:layout_height="200dp" android:src="@drawable/your_drawable" android:stateListAnimator="@anim/bounce" /> 

and rebound

 <?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> 
0
source

All Articles