animation does not start in canvas on android - android

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

Related

Animate change of view background not happening smoothly

I am trying to animate the back ground of my activity
What i have done is
ImageView image = (ImageView) findViewById(R.id.toggle_image);
final TransitionDrawable td = new TransitionDrawable( new Drawable[] {
getResources().getDrawable(R.drawable.welcomeimagetoggle1),
getResources().getDrawable(R.drawable.welcomeimagetoggle2)
});
image .setImageDrawable(td);
td.startTransition(3000);
td.reverseTransition(3000);
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 100ms
td.startTransition(3000);
td.reverseTransition(3000);
handler.postDelayed(this, 3000);
}
}, 3000);
It's working properly but the problem is while the timer ends the change happening is to smooth , there is a sudden movement. How can i avoid that ?
I think you should use this library (DexMovingImageView) instead.
It offers some cool transitions (check their demo). In your case, use the DexCrossFadeImageView with multiple images.
Don't forget to make the window background of your activity transparent to avoid overdraw.
UPDATE : About the padding, check the scaletype. As for animation, here's KenBurnsView (ImageView animated by Ken Burns effect), Motion (ImageView with a parallax effect that reacts to the device's tilt) and finally LoyalNativeSlider (An image slider with many cool animations). Hope this helps!

Is there any way to create skew animation for a View with ObjectAnimator in android

I want to create skew animation for a View in android.
So, I have rectangular view (this is normal/start state), at the end it should looks like this:
I can do such a thing with android.view.animation package using Transformation of TYPE_MATRIX. So I can create Matrix and use preSkew method, apply this Matrix to my custom animation and then start this animation on a view. So this is OK.
BUT
The problem is I want to do this with ObjectAnimator.
Because using android.view.animation package is not recommended to use.
But I can't get the solution for this problem with ObjectAnimator class.
If I have ImageView, I can use method setImageMatrix for ObjectAnimator (and also create custom MatrixEvaluator to evaluate corresponding matrices for each factor),
but I want to get solution for this problem with a View class, not for some subclass of it.
And the main reason is, that TextView, for example, doesn't have public method like setMatrix, and I want to get the solution for TextView too. So get the solution for base View class is the main desire.
There is another solution: create custom, for example, SkewTextView, in which onDraw method we use canvas.skew method.
But this is worse solution even than using android.view.animation package, because you need to create wrappers for any View subclass you want to skew.
So, I don't know, how I can skew View with a ObjectAnimator (as View class doesn't have public methods like setSkew or setMatrix).
How would you solve this problem?
Have you any idea of how to solve this problem?
Is there a solution for this problem with ObjectAnimator?
Any help (or even thoughts) is greatly appreciated
Thanks
Well without subclassing this might be a bit tricky. My main idea is to use TimeAnimator, which will provide you time callbacks in conjunction with Camera (which can use Matrix transformations). Or you can use TimeAnimator and make a Bitmap from the View you want to skew, make the original View invisible, and draw the Bitmap on each TimeAnimator step applying a Matrix to it. But I'm not sure if this is the optimal way to do that, since you will have to create a new Bitmap on each frame
EDIT: No, Camera approach is not the way to do that as it is stated in comments below
I created a skew animation using Android Property Animation APIs in my project (GitHub Link).
What I did:
Created a custom view (SkewView) and added a SKEW_X property to it.
public class SkewView extends ImageView {
private static final String TAG = "SkewView";
public static final Property SKEW_X
= new FloatProperty("skewX") {
#Override
public void setValue(SkewView object, float value) {
object.setSkewX(value);
}
#Override
public Float get(SkewView object) {
return object.getSkewX();
}
};
private float mSkewX;
// ...
public float getSkewX() {
return mSkewX;
}
public void setSkewX(float skewX) {
mSkewX = skewX;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
if (mSkewX != 0) {
canvas.skew((float) (mSkewX * Math.PI / 180.0f), 0);
}
super.onDraw(canvas);
}
}
Used ObjectAnimator to animate this property.
ObjectAnimator skewAnimator = ObjectAnimator.ofFloat(mTarget, SkewView.SKEW_X, 30);

Create animation in imageviews

I have an imageview with a default image. Now when I try to click it, I want it to animate that displays 4 frames of images. How could I accomplish this, I tried a simpler approach (more of a dumb approach) by changing the imageresource 4 times, as expected the image changes so fast that the animating image effect is not visible. Any ideas?
I tried this approach:
Gem = (ImageView)v;
Gem.setImageResource(com.example.gems.R.drawable.bd1);
Gem.postDelayed(new Runnable() {
public void run() {
Gem.setImageResource(com.example.gems.R.drawable.bd2);
Gem.postDelayed(new Runnable() {
public void run() {
Gem.setImageResource(com.example.gems.R.drawable.bd3);
Gem.postDelayed(new Runnable() {
public void run() {
Gem.setImageResource(com.example.gems.R.drawable.bd4);
Gem.postDelayed(new Runnable() {
public void run() {
}
}, 500);
}
}, 500);
}
}, 500);
}
}, 500);
It worked, but is there a better way to this without coding too much lines? I have 25 kinds of images and each image has 4 frames.
EDIT:
I tried using xml transition files:
Java file:
Resources res = this.getResources();
Gem = (ImageView)v;
TransitionDrawable transition;
transition = (TransitionDrawable)
res.getDrawable(R.drawable.blue_diamond_animation);
Gem.setImageDrawable(transition);
transition.startTransition(3000);
xml file:
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/bd1"></item>
<item android:drawable="#drawable/bd2"></item>
<item android:drawable="#drawable/bd3"></item>
<item android:drawable="#drawable/bd4"></item>
<item android:drawable="#drawable/invi"></item>
</transition>
This seems to work, but I don't want to draw this images in a transition. I want to change the background in a transition. I tried changing this android:drawable to android:drawable but it doesn't work.
It turns out that there is an exact class for this: AnimationDrawable
Basically, just add frames with the other pictures to use in the animation to the AnimationDrawable object and specify how long they should display using addFrame(Drawable frame, int duration)
Then set the ImageView to display whatever image it should start with and set the background to the AnimationDrawable you just made using setBackgroundDrawable(Animation)
Lastly, start the animation in the onClick listener
EDIT: FOR EXAMPLE
AnimationDrawable ad = new AnimationDrawable();
ad.addFrame(getResources().getDrawable(R.drawable.image1), 100);
ad.addFrame(getResources().getDrawable(R.drawable.image2), 500);
ad.addFrame(getResources().getDrawable(R.drawable.image3), 300);
ImageView iv = (ImageView) findViewById(R.id.img);
iv.setBackgroundDrawable(animation);
And then in your onClick listener, just call ad.start
It depends on what you are trying to accomplish. You have not given enough info to go on
The viewproperty animator is really the easiest thing to use have a look. It can also be used with older API's using nineoldandroids jar (google it)
http://developer.android.com/reference/android/view/ViewPropertyAnimator.html
The ObjectAnimator and ValueAnimator are also available similar and slightly more difficult to implement
http://developer.android.com/reference/android/animation/ObjectAnimator.html
http://developer.android.com/reference/android/animation/ValueAnimator.html
Have a look at the APIdemos in the sample packs there are a few examples mainly using the ValueAnimator.
http://developer.android.com/tools/samples/index.html
There are also Sprites to consider but it is basically a bitmap , you can user the timer obect to choreograph

invalidate() on custom View does not cause onDraw(Canvas c) to be called

For my activity i use 3 custom views stacked.
the lower one is a SurfaceView fullscreen, the middle one is derived from GridView and overrides onDraw to add custom graphic.
The top one is derived directly from View, sits in a corner of the screen and act as a knob to control the others two views (this is the problematic view).
to add a custom animation to this view, i used this pattern:
public class StubKnobView extends View{
private Drawable knob;
private Point knobPos;
private float rotation;
private boolean needsToMove;
public void moveKnob(){
/* ...various calculations... */
this.needsToMove=true;
invalidate(); //to notify the intention to start animation
}
private void updateAnimation(){
/* ........... */
this.needsToMove= !animationComplete;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
int saveCount=canvas.getSaveCount();
canvas.save();
canvas.rotate(this.rotation, this.knobPos.x, this.knobPos.y );
this.knob.draw(canvas);
canvas.restoreToCount(saveCount);
if(this.needsToMove){
updateAnimation();
}
}
}
ideally, if there is an animation pending, after each drawing cycle the view should auto invalidate.
right now this doesn't work, to force the animation i have to touch the screen to cause a onDraw cycle.
Using "show screen updates" of Dev tools I see that no screen invalidate/update cycle happen , apart when i click the screen.
specifying the dirty rect also ha no effect.
So, any idea where to look to know why this invalidate/draw cycle does not work the way is intended?
I encontered this situation, and also doubted that invalidate() doesn't make onDraw() called again.
After simplified the business codes, it's turn out that there is a dead loop - exactly too much iterations, which blocks the UI thread.
So, my advice is that make sure the UI thread going smoothly first.
Try something like this with a private class in your View. The idea is not to call invalidate() from within onDraw(). Instead, post it on the running queue. Instantiate the private class in your View constructor and then just call animateKnob.start() when you want the animation. The onDraw() can then just focus on drawing.
public void moveKnob(){
// update the state to draw... KnobPos, rotation
invalidate()
}
private class AnimateKnob{
public void start(){
// Do some calculations if necessary
// Start the animation
MyView.this.post( new Runnable() {
stepAnimation()
});
}
public void stepAnimation(){
// update the animation, maybe use an interpolator.
// Here you could also determine if the animation is complete or not
MyView.this.moveKnob();
if( !animationComplete ){
// Call it again
MyView.this.post( new Runnable() {
stepAnimation()
});
}
}
}

Android animate character in SurfaceView

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.

Categories

Resources