I have created an object of AnimationDrawable with Bitmap frames.
Next what I want to do is, to perform a function every time the Frame changes in that Animation. But I have no idea how I will be able to achieve this.
Is there any inbuilt or custom method available through which we can get triggered for frame change? Please help!
To create and start the Animation, I have used code as below:
int duration = 200;
Animation myAnim = new AnimationDrawable();
for (Bitmap frame : framesList) {
myAnim.addFrame(new BitmapDrawable(frame), duration);
}
if (android.os.Build.VERSION.SDK_INT <=
android.os.Build.VERSION_CODES.JELLY_BEAN)
imgPicture.setBackgroundDrawable(myAnim);
else
imgPicture.setBackground(myAnim);
myAnim.start();
Related
I have an ImageView that is being used to show some frame animation.
The Duration for these images are all set to 100.
However, the ImageView needs to be hidden sometimes. So the animation is stopped and the ImageView is set to GONE.
When it's time to show the ImageView again, its visibility is set to VISIBLE and the animation is started.
HOWEVER - now the animation is really fast; instead of a duration of 100, it looks like 50. But when I check the duration it still says 100 - but it definitely doesn't look like it.
The code to hide and show the ImageView is as follows:
//hide the animation
final AnimationDrawable frameAnim = (AnimationDrawable) animImgView.getBackground();
if (frameAnim.isRunning() == true)
{
frameAnim.stop();
}
frameAnim.setVisible(false, false);
animImgView.setVisibility(View.GONE);
//show animation
animImgView.setVisibility(View.VISIBLE);
final AnimationDrawable frameAnim = (AnimationDrawable) animImgView.getBackground();
frameAnim.setVisible(true, true);
frameAnim.start();
What could be the trouble ?
After some experimentation I found that the best way is to simply implement:
//hide the animation
animImgView.setVisibility(View.GONE);
//show animation
animImgView.setVisibility(View.VISIBLE);
this will preserve the animation speed. My original intent with the animation stop/start was to ensure the CPU wasn't doing more than was needed.
To achieve the original goal of not just changing visibility, but also stopping the animation when invisible:
//hide the animation
animImgView.setVisibility(View.GONE);
//stop animation
final AnimationDrawable frameAnim = (AnimationDrawable) animImgView.getBackground();
if (frameAnim.isRunning() == true)
{
frameAnim.stop();
}
frameAnim.setVisible(false, false);
//start animation
final AnimationDrawable frameAnim = (AnimationDrawable) animImgView.getBackground();
frameAnim.setVisible(true, true);
frameAnim.start();
//show animation
animImgView.setVisibility(View.VISIBLE);
The difference here is that starting and stopping the animation occurs while the ImageView is invisible/gone. For some reason, starting and stopping the animation when it is visible causes the timing issues.
Source: I ran into this problem myself and fixed it using this technique.
Struggling with Android I found next solution:
don't use start() and stop() methods.
Use setVisible(true, true) to start animation:
animImgView.setVisibility(View.VISIBLE);
final AnimationDrawable frameAnim = (AnimationDrawable) animImgView.getBackground();
frameAnim.setVisible(true, true);
and setVisible(false, true) to stop it (note the bold true):
final AnimationDrawable frameAnim = (AnimationDrawable) animImgView.getBackground();
frameAnim.setVisible(false, true);
animImgView.setVisibility(View.GONE);
I would like to animate some images.
Could someone tell me why this first piece of code does not work, but the second one does work ?
And if I have to use the second one, how do I STOP the animation into the runnable ?
EDIT : the first code works on android 4.x, but not on 2.2 (both simulator and device)
code 1 (into "onCreate()" ):
ImageView boule = (ImageView)findViewById(R.id.boule);
boule.setImageBitmap(null);
boule.setBackgroundResource(R.anim.anime);
AnimationDrawable animation = (AnimationDrawable)boule.getBackground();
animation.start();
// does not animate anything...
code 2 (also into "onCreate()" ) :
ImageView boule = (ImageView)findViewById(R.id.boule);
boule.setImageBitmap(null);
boule.setBackgroundResource( R.anim.anime );
final AnimationDrawable animation = (AnimationDrawable) boule.getBackground();
boule.post(new Runnable() {
public void run() {
if ( animation != null ) animation.start();
}
});
// OK, it works, but how do I stop this ?
You can try this.. this code works properly
BitmapDrawable frame1 = (BitmapDrawable)getResources().getDrawable(R.drawable.jth);
BitmapDrawable frame2 = (BitmapDrawable)getResources().getDrawable(R.drawable.jthj);
int duration = 10;
final AnimationDrawable ad = new AnimationDrawable();
ad.setOneShot(false);
ad.addFrame(frame1, duration);
ad.addFrame(frame2, duration);
iv.setBackgroundDrawable(ad);
ad.setVisible(true, true);
Put ad.start(); in button onClickListener and ad.stop(); for stop animantion
I have a frame-by-frame animation and I want to set a specific frame when the stop method has been called. I searched a lot but I haven't found what I was serching for.
Does this method exists? Is it possible to do that?
Use this method on your AnimationDrawable: animationDrawable.selectDrawable(index)
Assuming that frame-by-frame means AnimationDrawable given in the background of an ImageView.
Like that (or via xml):
AnimationDrawable animationDrawable = new AnimationDrawable();
animationDrawable.addFrame(drawableFrame1, 0);
animationDrawable.addFrame(drawableFrame2, 1);
animationDrawable.addFrame(drawableFrame3, 2);
animationDrawable.addFrame(drawableFrame4, 3);
iv = new ImageView(this);
iv.setBackgroundDrawable(animationDrawable);
Here is the code to retrieve a given frame and set it to the background of the ImageView
onStop() {
Drawable drawableFrame2 = ((AnimationDrawable)iv.getBackground()).getFrame(2);
iv.setBackgroundDrawable(drawableFrame2);
iv.postInvalidate();
}
I want to animate a character (for eg run a dog) on screen. AnimationDrawable seemed a perfect fit for this, and AnimationDrawable requires an ImageView. How do I add and move around the ImageView in SurfaceView?
Thanks.
You don't need an ImageView.
If your animation is an XML Drawable, you can load it directly from the Resources into an AnimationDrawable variable:
Resources res = context.getResources();
AnimationDrawable animation = (AnimationDrawable)res.getDrawable(R.drawable.anim);
Then set it's bounds and draw on the canvas:
animation.setBounds(left, top, right, bottom);
animation.draw(canvas);
You also need to manually set the animation to run on it's next scheduled interval. This can be accomplished by creating a new Callback using animation.setCallback, then instantiating an android.os.Handler and using the handler.postAtTime method to add the next animation frame to the current Thread's message queue.
animation.setCallback(new Callback() {
#Override
public void unscheduleDrawable(Drawable who, Runnable what) {
return;
}
#Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
//Schedules a message to be posted to the thread that contains the animation
//at the next interval.
//Required for the animation to run.
Handler h = new Handler();
h.postAtTime(what, when);
}
#Override
public void invalidateDrawable(Drawable who) {
return;
}
});
animation.start();
With a SurfaceView it is your responsibility to draw everything within it. You do not need AnimationDrawable or any view to render your character on it. Take a look onto Lunar Lander example game from Google.
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
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.
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();
}
});
```
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 :-)
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.
Lars Blumberg's answer is correct but the documentation is incorrect; you also need to take into account this: animation start issue