What is the optimal way to animate a drawable within a view using the animator classes?
android, animation, drawing, hardware-acceleration
Solution
With the use of the Object Property Animators, basically they're just math functions that repeatedly call a "setN()" method every X miliseconds where "N" is the property you want to change.
In the example provided in the case of alpha, both would require a call to `invalidate()` to redraw the View that you are animating. The difference being when you call `setAlpha()` on the `View` object, it calls `invalidate()` for you. If you were to set the target Object to the `Paint` object that is used to draw the drawable, you would still need to call `invalidate()` on the `View` so it will redraw with the new `Paint` parameters.
Ideally you want to set the target to the highest level child you can so the redrawing only happens on the views you want to animate. If you set the target to the root View, for example, it will call `invalidate()` on every child in the entire ViewGroup which will in turn call `draw()` on every child in the ViewGroup. If you set it to a top level `ImageView`, then only `ImageView` will be redrawn.
To best utilize the Hardware, you need to use the Layer properties. First, you need to decide what the top-most parent View you want to animate will be. If you want to only fade the `Drawable`, then it will be the `Drawable` or containing `View`. If you want to fade everything, then it will be the root view. Whatever you decide to animate will be applied to the `View` as a whole at once.
Use `setLayerType()` on the parent view just before you start the Animator. Set it to `View#LAYER_TYPE_HARDWARE`. Then set an `AnimationListener` and reset the LayerType to `View#LAYER_TYPE_SOFTWARE` or `View#LAYER_TYPE_NONE` upon completion of the animator.
myParentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
myObjectAnimator.addListener(new ViewAnimator.AnimatorListener() {
public void onAnimationEnd(Animator animation) {
myParentView.setLayerType(View.LAYER_TYPE_NONE);
}
public void onAnimationRepeat(Animator animation) {
}
public void onAnimationStart(Animator animation) {
}
public void onAnimationCancel(Animator animation) {
myParentView.setLayerType(View.LAYER_TYPE_NONE, null);
}
}
myObjectAnimator.start();
In this case, if you were to translate `myParentView` by using the `translateX` property, then it will put layer `myParentView` and all it's children into one plane. Put it in to hardware memory. Translate the entire view all at once. Then, upon completion, remove `myParentView` from memory.
EDIT:
One final note, Alpha wreaks havoc on the CPU. If you have something on half-alpha and translate it across the View, it will be harder to render than if you simply translate the View. Use it sparingly.
Problem
I have read about Property Animation and Hardware Acceleration but I am still uncertain what is the most efficient way to use the animator classes. (For the sake of this question I don't need to support devices before Honeycomb. So I want to use the animator classes.) For example, say I have a View. In this view I have a BitmapDrawable that I want to fade in. There are also many other elements within the view that won't change. What property or object would be best to use with the animator? The drawable? A paint that I am drawing the bitmap with in onDraw? Something else? How can this be done to be most efficient with hardware acceleration? Will this require calling invalidate for each step of the animation or is there a way to animate just the drawable and not cause the rest of the view to be redrawn completely for each step of the animation? I guess I imagine an optimal case would be the rest of the view not having to be completely redrawn in software, but rather hardware acceleration efficiently fading the drawable. Any suggestions or pointers to recommended approaches? Thanks!