2
votes

I'm working on a game that requires drawing to SurfaceView's Canvas. I'm using SurfaceHolder to obtain Canvas to draw to, and perform drawing in a separate thread. Everything I draw displays correctly except for this one animation.

Here is the animation definition (it is in res/drawable/ my_animation.xml:

and here is how I draw it to the Canvas:

AnimationDrawable ad = (AnimationDrawable)getResources().getDrawable(R.drawable.my_animation); ad.draw(canvas); ad.start();

but only the first frame ever appears on the screen.

What am I missing?

Thank you

5

5 Answers

2
votes

If I get the reference right, you have to assign your AnimationDrawable to an ImageView as the example from http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html demonstrates:

// Load the ImageView that will host the animation and
// set its background to our AnimationDrawable XML resource.
ImageView img = (ImageView)findViewById(R.id.spinning_wheel_image);
img.setBackgroundResource(R.drawable.spin_animation);

// Get the background, which has been compiled to an AnimationDrawable object.
AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground();

// Start the animation (looped playback by default).
frameAnimation.start()

In your case you did not assign your AnimationDrawable to any view so I suppose that's why it does not get updated. So you have to call AnimationDrawable.getFrame(int) manually.

If you are already using a separate thread why don't you involve also the code for your animation? This would render your code more consistent in my opinion.

2
votes

Although this is an old question, i run into this problem too and figure out a walkaround, so i just post it here in case anyone searching about.

```java

final AnimationDrawable animationDrawable = ...;

final View v = new View(this) {

    @Override
    protected void onDraw(Canvas canvas) {
        animDrawable.draw(canvas);
    }

};

animationDrawable.setCallback(new Callback() {

    @Override
    public void unscheduleDrawable(Drawable who, Runnable what) {
        v.removeCallbacks(what);
    }

    @Overridew
    public void scheduleDrawable(Drawable who, Runnable what, long when) {
        v.postDelayed(what, when - SystemClock.uptimeMillis());
    }

    @Override
    public void invalidateDrawable(Drawable who) {
        v.postInvalidate();
    }
});

```

1
votes

Animated drawables of all kinds (Transition, etc.) need a Callback to schedule redrawals. As zhang demonstrates, it is a simple interface for posting Runnables.

To support animated drawables in a custom view, you need two things:

  • pass your View to your animated Drawable's setCallback. Even base View implements Drawable.Callback, so there's no need to write your own wrapper.
  • override verifyDrawable to also return true for your animated Drawable.

As to why anyone would need that - I have just implemented animated drawable support in RecyclerView.ItemDecorations, how cool is that :-)

0
votes

You are working with Canvas means, you are coding in low level. In low level u have to do everything. working with View (ImageView) means, it is high level.In ImageView already defined in low level on canvas how to deal with AnimationDrawable.

0
votes

Lars Blumberg's answer is correct but the documentation is incorrect; you also need to take into account this: animation start issue