How to animate on Android
Previously I have described how to create animations for both native Android and React Native applications using OpenGL. This time I’d like to tell about different tools which could be useful for Android animations of any difficulty and their pros and cons. This article is not a tutorial or something similar; it is a small collection of my thoughts and recommendations about animating in Android.
Tools I don’t use
However, the first thing I’d like to start from is tools, which I don’t use, and why. Some of them I used in my opensource animations, but I don’t want to use them further. Of course, it’s just my subjective opinion, and it’s not a call for refactoring of your recent animation :)
ObjectAnimator
ObjectAnimator.ofFloat(image, "x", 0f, 300f).apply {
duration = 1000
start()
}
The code snippet above shows usage of the ObjectAnimator
. In this case, the x
property of my image
changes through reflection, which is not a good idea while animating. The reflection mechanism is great, but it’s a bit overhead for simple animations. Of course, we can solve that by using the Property
instead of hardcoding the property name.
ObjectAnimator.ofFloat(image, View.X, 0f, 300f).apply {
duration = 1000
start()
}
Now the property value changes using appropriate setter directly without reflection. So right now we can see the first small disadvantage of the ObjectAnimator
— you need to create Property
for every custom property you want to modify to avoid using reflection.
The other issue is that you need a new ObjectAnimator
for every view you want to modify since it doesn’t support simultaneous changes of several objects.
Anyway, it worth to say that ObjectAnimator
is widely used in AnimatedVectorDrawable
to animate SVG due to its ability to animate a property of any type. In my opinion, in any other case, there are better solutions for animations.
Animation and its subclasses
image.startAnimation(TranslateAnimation(0f, 300f, 0f, 0f).apply {
duration = 1000
})
Animation
is the abstract parent class of TranslateAnimation
, RotateAnimation
, AlphaAnimation
, ScaleAnimation
and AnimationSet
.
They could be useful to animate single view property, in any other circumstances Animation
subclasses require to setup several instances to play AnimationSet
just like ObjectAnimator
does. And another big disadvantage is that you can animate only basic properties like rotation, scale, alpha and position (e.g., not a background color) and these tools are restricted to View
's subclasses only. One more issue you face if you use Animation
is that it animates a View
's pixel only, not a View
itself, e.g., you apply TransitionAnimation
to your object, but it stays clickable in the previous location, if not to specify different behavior.
For now, the only reasonable usage of the Animation
is the transitions between activities or fragments.
ViewPropertyAnimator
ViewPropertyAnimator
is created to substitute the ObjectAnimator
, and it’s adapted to simultaneous modifications due to optimization of the invalidate()
method calls, which doubtlessly is good news. It’s a great tool, to animate several properties of a view in parallel.
image.animate().apply {
duration = 1000
x(300f)
y(150f)
alpha(0.5f)
start()
}
It looks much better, isn’t it? But usually animation requires to animate several views at the same time and not only views but other objects, so it’s still not good enough.
Tools I use
While reading the previous part, you may think that I’m too exacting to these instruments. But in most cases, they could be easily replaced by ValueAnimator
.
ValueAnimator
ValueAnimator.ofFloat(0f, 300f).apply {
duration = 1000
addUpdateListener {
image.x = it.animatedValue as Float
anotherImage.y = interpolate(100f, 500f, it.animatedFraction)
}
start()
}fun interpolate(a: Float, b: Float, f: Float) = a + f * (b - a)
So, ValueAnimator
allows us to animate any number of objects of any type at the same time using one instance of it. And you can use not only the animated value but the fraction to be able to interpolate between other two values without creating a new instance of ValueAnimator
. Great!
Both parts (record button and countdown) of the animation above are implemented using ValueAnimator
.
Take a look at another animation created with ValueAnimator
for Yalantis and its source code:
When to use:
1. For animations of simple and middle difficulty, which transformations are possible to represent as linear or any other mathematical function.
Physics-based animations
Recently a new tool for animations on Android was introduced to developers — Physics-based Animations. A great thing, which helps to make objects move physically plausible without overhead like a physical engine in simple animations. It consists of two main classes — SpringAnimation
and FlingAnimation
.
Using SpringAnimation
, you can make your View
move like a spring with specified damping
, stiffness
and final position
:
SpringAnimation(image, DynamicAnimation.TRANSLATION_Y, 700f).apply {
spring.stiffness = 40f
spring.dampingRatio = 0.2f
}.start()
FlingAnimation
helps to create smoother and more feasible fling movement of the View
. Its start velocity
and friction
are possible to customize.
FlingAnimation(image, DynamicAnimation.TRANSLATION_X).apply {
startVelocity = 100 // pixels per second
friction = 0.5f
}.start()
When to use:
1. For animations, which require objects move in a physically realistic way without complex interaction with other objects (e.g., collisions)
Canvas
As I’ve mentioned earlier, sometimes, it’s not enough to animate View
's subclasses only. To draw all the stuff by yourself, you need to use Canvas
, which is accessible in onDraw()
method of any View
. It allows drawing anything from simple circle to bezier curves or text.
path.apply {
moveTo(0f, 0f)
lineTo(width.toFloat(), 0f)
lineTo(width.toFloat(), height.toFloat())
lineTo(0f, height.toFloat())
quadTo(0f, height / 2f, 150f, 0f)
}
canvas?.drawPath(path, paint)
Path
and Paint
are helper classes of Canvas
, which contains geometric paths and style data respectively.
Check out my animation created using features of Canvas
and ValueAnimator
:
Canvas
is a great tool and it works quite fast, but for small areas. If you try to use it to draw the whole screen, you’ll notice that every frame is drawn for more than 16 ms, which causes animation glitches.
When to use:
1. For more complex animations, which are not possible/easy to represent as a combination of views.
OpenGL
OpenGL is a heavy artillery in Android animations. It’ll work fine when Canvas
can’t cope with significant areas of drawing.
The usage of OpenGL is becoming wider every year — games, difficult 2D and 3D animations, photo and video effects, augmented reality and virtual reality applications. Don’t lose your time, start learning OpenGL today!
To find out about basics in OpenGL and to check out the example animation review my article:
Also, I highly recommend to read this book to get more acquainted with OpenGL:
This tool is convenient to check your shaders or share them with your friends or colleagues:
When to use:
1. For huge and continuously rendering animations
2. For 3D animations
3. For animations with complex transformations
Physics engines
To create difficult physically plausible animations with interactions between objects, you’ll certainly need to use a physics engine.
I chose Box2D for myself. It’s a C++ library, which has plenty of ports in another programming languages, and if you’re acquainted with one of them, you can work with any one. It’s very lightweight and doesn’t require you to make any architectural changes (as opposite to LibGDX, which is quite good for games though). Also, its community is quite large, and you can find an answer for any question independently from the platform and programming language.
You can use the original native library or its Java port called JBox2D on Android.
When to use:
1. For simple 2D games
2. For advanced animations, which require complex interactions between objects
Interpolators
One of the main things you need to learn to create animations is interpolators. They are used in animations on every platform and in any programming language. Interpolator describes how your animation value will be changed during the timeline. You can find some ready interpolators in Android SDK like AccelerateInterpolator
, DecelerateInterpolator
, AccelerateDecelerateInterpolator
, OvershootInterpolator
, etc. To learn about the difference between them check out this article:
To dive a bit deeper read this article:
To create one on Android, you need to implement Interpolator interface.
class CustomInterpolator: Interpolator {
override fun getInterpolation(input: Float): Float {
// todo return your function value
}
}
After that you can use it with ValueAnimator
:
ValueAnimator.ofFloat(0f, 300f).apply {
duration = 1000
interpolator = CustomInterpolator()
addUpdateListener {
image.x = it.animatedValue as Float
anotherImage.y = interpolate(100f, 500f, it.animatedFraction)
}
start()
}fun interpolate(a: Float, b: Float, f: Float) = a + f * (b - a)
I can recommend you a quite useful tool to help you to create your interpolator, where you can see an animated example of any interpolator:
Also, you can use PathInterpolator
to generate custom interpolator at the runtime by the control points of the needed bezier curve:
interpolator = PathInterpolator(0f, 0.3f, 0.1f, 0.2f)
This could replace the code above for pre-lollipop:
interpolator = PathInterpolatorCompat.create(0f, 0.3f, 0.1f, 0.2f)
As a conclusion, I’d like to say that there is no one universal tool or advice on how to create animations on Android, the solution depends on the many circumstances a lot — e.g., the difficulty of a component, time resources availability, etc. Every time weigh the advantages and disadvantages before making the choice of instruments.
It seems like that’s all for now. Thank you for reading my article and have fun with animations! :)