Android Animation Tutorial with Kotlin
In this Android animation tutorial, you will learn how to use property animations to make a fun, beautiful user interface. By Kevin D Moore.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Android Animation Tutorial with Kotlin
35 mins
- Getting Started
- How do Property Animations Work?
- Time Interpolators
- Your First Animation
- Launch the Rocket
- Put a Spin on It
- Accelerate the Launch
- Which Properties Can You Animate?
- ObjectAnimator
- Animating Color
- Combining Animations
- ViewPropertyAnimator
- Animating the Same Property of Two Objects
- Animation Listeners
- Animation Options
- Declaring Animations in XML
- Where To Go From Here?
Animating Color
Speaking of use cases, there’s animating colors to consider. Neither ofFloat()
nor ofInt()
can construct your animator and get good results with colors. You’re better off using ArgbEvaluator
.
Open ColorAnimationActivity.kt and put this code into onStartAnimation()
:
//1
val objectAnimator = ObjectAnimator.ofObject(
frameLayout,
"backgroundColor",
ArgbEvaluator(),
ContextCompat.getColor(this, R.color.background_from),
ContextCompat.getColor(this, R.color.background_to)
)
// 2
objectAnimator.repeatCount = 1
objectAnimator.repeatMode = ValueAnimator.REVERSE
// 3
objectAnimator.duration = DEFAULT_ANIMATION_DURATION
objectAnimator.start()
In the code above, you:
- Call
ObjectAnimator.ofObject()
and give it the following arguments:-
frameLayout
— the object with the property to be animated. -
"backgroundColor"
— the property you want to animate. -
ArgbEvaluator()
— an additional argument that specifies how to interpolate between two different ARGB (alpha, red, green, blue) color values. - Start and end color values — here you make use of
ContextCompat.getColor()
to get the color resource id of a custom color specified in your colors.xml.
-
- Set the number of times the animation will repeat by setting the object’s
repeatCount
value. Then you set itsrepeatMode
to define what the animation does when it reaches the end. More on this soon! - Set duration and start the animation.
Build and run. Pick the Background color item and tap on the screen.
That’s amazing! Hey, you’re getting the hang of this pretty quickly. That’s a buttery-smooth background color change :]
Combining Animations
Animating a view is pretty awesome, but so far you’ve changed only one property and one object at a time. Animations need not be so restrictive.
It’s time to send Doge to the moon! :]
AnimatorSet
allows you to play several animations together or in sequence. You pass your first animator to play()
, which accepts an Animator
object as an argument and returns a builder.
Then you can call the following methods on that builder, all of which accept Animator
as an argument:
-
with()
— to play theAnimator
passed as the argument simultaneously with the first one you specified inplay()
. -
before()
— to play it before. -
after()
— to play it after.
You can create chains of calls such as these.
Open LaunchAndSpinAnimatorSetAnimatorActivity.kt in your editor, and put the following code into onStartAnimation()
:
// 1
val positionAnimator = ValueAnimator.ofFloat(0f, -screenHeight)
// 2
positionAnimator.addUpdateListener {
val value = it.animatedValue as Float
rocket.translationY = value
}
// 3
val rotationAnimator = ObjectAnimator.ofFloat(rocket, "rotation", 0f, 180f)
// 4
val animatorSet = AnimatorSet()
// 5
animatorSet.play(positionAnimator).with(rotationAnimator)
// 6
animatorSet.duration = DEFAULT_ANIMATION_DURATION
animatorSet.start()
Here’s what you’re doing in this block:
- Create a new
ValueAnimator
. - Attach an
AnimatorUpdateListener
to theValueAnimator
that updates the rocket’s position. - Create an
ObjectAnimator
, a second animator that updates the rocket’s rotation. - Create a new instance of
AnimatorSet
. - Specify that you’d like to execute
positionAnimator
together withrotationAnimator
. - Just as with a typical animator, you set a duration and call
start()
.
Build and run again. Select the Launch and spin (AnimatorSet). Tap the screen.
Doge defies the laws of physics with this one.
There’s a nifty tool to simplify animating several properties of the same object. The tool is called…
ViewPropertyAnimator
One of the greatest things about animation code that uses ViewPropertyAnimator
is that it’s easy to write and read — you’ll see.
Open LaunchAndSpinViewPropertyAnimatorAnimationActivity.kt and add the following call to onStartAnimation()
:
rocket.animate()
.translationY(-screenHeight)
.rotationBy(360f)
.setDuration(DEFAULT_ANIMATION_DURATION)
.start()
In here, animate()
returns an instance of ViewPropertyAnimator
so you can chain the calls.
Build and run, select Launch and spin (ViewPropertyAnimator), and you’ll see the same animation as in the previous section.
Compare your code for this section to the AnimatorSet
code snippet that you implemented in the previous section:
val positionAnimator = ValueAnimator.ofFloat(0f, -screenHeight)
positionAnimator.addUpdateListener {
val value = it.animatedValue as Float
rocket?.translationY = value
}
val rotationAnimator = ObjectAnimator.ofFloat(rocket, "rotation", 0f, 180f)
val animatorSet = AnimatorSet()
animatorSet.play(positionAnimator).with(rotationAnimator)
animatorSet.duration = DEFAULT_ANIMATION_DURATION
animatorSet.start()
ViewPropertyAnimator
may provide better performance for multiple simultaneous animations. It optimizes invalidated calls, so they only take place once for several properties — in contrast to each animated property causing its own invalidation independently.
Animating the Same Property of Two Objects
A nice feature of ValueAnimator
is that you can reuse its animated value and apply it to as many objects as you like.
Test it out by opening FlyWithDogeAnimationActivity.kt and putting the following code in onStartAnimation()
:
//1
val positionAnimator = ValueAnimator.ofFloat(0f, -screenHeight)
positionAnimator.addUpdateListener {
val value = it.animatedValue as Float
rocket.translationY = value
doge.translationY = value
}
//2
val rotationAnimator = ValueAnimator.ofFloat(0f, 360f)
rotationAnimator.addUpdateListener {
val value = it.animatedValue as Float
doge.rotation = value
}
//3
val animatorSet = AnimatorSet()
animatorSet.play(positionAnimator).with(rotationAnimator)
animatorSet.duration = DEFAULT_ANIMATION_DURATION
animatorSet.start()
In the above code you just created three animators:
-
positionAnimator
— for changing positions of bothrocket
anddoge
. -
rotationAnimator
— for rotating Doge. -
animatorSet
— to combine the first two animators.
Notice that you set translation for two objects at once in the first animator.
Run the app and select Don’t leave Doge behind (Animating two objects). You know what to do now. To the moon!
Animation Listeners
Animation typically implies that a certain action has occurred or will take place. Typically, whatever happens usually comes at the end of your fancy animation.
You don’t get to observe it, but know that the rocket stops and stays off screen when the animation ends. If you don’t plan to land it or finish the activity, you could remove this particular view to conserve resources.
AnimatorListener
— receives a notification from the animator when the following events occur:
-
onAnimationStart()
— called when the animation starts. -
onAnimationEnd()
— called when the animation ends. -
onAnimationRepeat()
— called if the animation repeats. -
onAnimationCancel()
— called if the animation is canceled.
Open WithListenerAnimationActivity.kt and add the following code to onStartAnimation()
:
//1
val animator = ValueAnimator.ofFloat(0f, -screenHeight)
animator.addUpdateListener {
val value = it.animatedValue as Float
rocket.translationY = value
doge.translationY = value
}
// 2
animator.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {
// 3
Toast.makeText(applicationContext, "Doge took off", Toast.LENGTH_SHORT)
.show()
}
override fun onAnimationEnd(animation: Animator) {
// 4
Toast.makeText(applicationContext, "Doge is on the moon", Toast.LENGTH_SHORT)
.show()
finish()
}
override fun onAnimationCancel(animation: Animator) {}
override fun onAnimationRepeat(animation: Animator) {}
})
// 5
animator.duration = 5000L
animator.start()
The structure of the code above, with the exception of the listener part, should look the same as the previous section. Here’s what you’re doing in there:
- Create and set up an animator. You use
ValueAnimator
to change the position of two objects simultaneously — you can’t do the same thing with a singleObjectAnimator
. - Add the
AnimatorListener
. - Show a toast message when the animation starts.
- And another toast when it ends.
- Start the animation as usual.
Run the app. Select Animation events. Tap on the screen. Look at the messages!
Alternatively, you can set start and end actions on your View by calling withStartAction(Runnable)
and withEndAction(Runnable)
after animate()
. It’s the equivalent to an AnimatorListener
with these actions.
ViewPropertyAnimator
by adding a setListener
to a call chain before calling start()
:
rocket.animate().setListener(object : Animator.AnimatorListener {
// Your action
})
Alternatively, you can set start and end actions on your View by calling withStartAction(Runnable)
and withEndAction(Runnable)
after animate()
. It’s the equivalent to an AnimatorListener
with these actions.
rocket.animate().setListener(object : Animator.AnimatorListener {
// Your action
})