user940016
user940016

Reputation: 2938

Making smooth animations

I have a property animation, but it's not smooth, i.e I'm getting jumps in the animation. I tried to play with the parameters for the animator, such as the interpolator, the duration, and the frame delay, but can't get a smooth effect. Does anyone have some tricks / examples? Here's my current code for setting the animator:

rotationAnimator=new ObjectAnimator();
rotationAnimator.setTarget(rotationController);
rotationAnimator.setPropertyName("mapRotation");
rotationAnimator.setInterpolator(new LinearInterpolator());
ValueAnimator.setFrameDelay(24);
rotationAnimator.setDuration(ROTATION_DURATION);
rotationAnimator.setRepeatCount(ValueAnimator.INFINITE);
rotationAnimator.setRepeatMode(ValueAnimator.RESTART);

(There's also a call to setFloatValues, but it comes later in the code, before I start the animation)

EDIT: I was asked to show what I'm animating, so here it is:

That's the setter function that gets the value from the animation:

public void setMapRotation(float rotationDegrees)
{
    if ((rotationAnimator!=null)&&(rotationAnimator.isRunning()))
        rotationAnimator.cancel();
    rotationDegrees%=360;
    if (rotationDegrees<0) rotationDegrees+=360;
    rotationView.setRotationDegrees(rotationDegrees);
    if (rotationDegrees!=oldRotationDegrees)
    {
        notifyRotationListeners();
        oldRotationDegrees=rotationDegrees;
    }
}

If you look at the code, you'll see there's another function that gets called (setRotationDegrees), so here it is:

public void setRotationDegrees(float rotationDegrees)
{ 
    this.rotationDegrees=rotationDegrees%360;
    if (this.rotationDegrees<0) this.rotationDegrees+=360;
    Log.i("MapView","View degrees: " + this.rotationDegrees);
    invalidate();
}

And that's what happens after the invalidation:

@Override protected void dispatchDraw(Canvas canvas)
{
    Log.i("MapView","Redrawing");
    int saveCount=canvas.save(Canvas.MATRIX_SAVE_FLAG);
    canvas.rotate(rotationDegrees,getWidth()/2,getHeight()/2);
    canvas.setDrawFilter(drawFilter);
    canvas.getMatrix(rotationMatrix);
    super.dispatchDraw(canvas);
    canvas.restoreToCount(saveCount);
}

I don't know if there's something particularly heavy here, but I may be wrong...

Upvotes: 1

Views: 8429

Answers (3)

christian mini
christian mini

Reputation: 1702

I've resolved by adding HW acceleration directly to my animated view and view container (myViewContainer - in my case a RelativeLayout):

if(!myViewContainer.isHardwareAccelerated())
{
    myViewContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
    myAnimatedView1.setLayerType(View.LAYER_TYPE_HARDWARE, null);
    myAnimatedView2.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}

Upvotes: 1

Emile
Emile

Reputation: 11721

Jumps in the middle of the animation are more likely to be caused by either something in your rotationController class, that is receiving the animated value "mapRotation". Or it could be something to do with your layout.

I would imagine that there is something quite intense, memory or cpu wise, that is causing the juttering.

If your animating something that has lots of layouts then that could be the cause. If in your code you have lots of findViewByID that is getting called as a result of your animation then that to can cause a slow down.

If your just animating a simple image, then im not entirely sure what the issue would be.

Personally i think your code looks fine, perhaps show/describe what your animating.

[edit] I have limited knowledge of animating with the canvas so i took a quick look at how you were using canvas.save() and canvas.restoreToCount() which i hadn't seen before.

It all looks good though i do find it odd that several tutorials rotate the canvas rather than the ball image to create the rotation. Still, the only reference i found to improving the animating was a comment in the following link that suggested using postInvalidateOnAnimation(). Not sure where though, perhaps instead of invalidate().

Upvotes: 0

ben75
ben75

Reputation: 28706

Defining an AnimatorSet and set the Interpolator on it may solve your issue:

rotationAnimator=new ObjectAnimator();
rotationAnimator.setTarget(rotationController);
rotationAnimator.setPropertyName("mapRotation");
ValueAnimator.setFrameDelay(24);
rotationAnimator.setDuration(ROTATION_DURATION);
rotationAnimator.setRepeatCount(ValueAnimator.INFINITE);
rotationAnimator.setRepeatMode(ValueAnimator.RESTART);

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.getChildAnimations().add(rotationAnimator);
animatorSet.setInterpolator(new LinearInterpolator());
...
animatorSet.start();

Upvotes: 1

Related Questions