Exploring the Android Lottie SDK

Enzo Belli
Yoyo Engineering
Published in
5 min readMar 1, 2019

I’ve always been fascinated by those apps with cool animations and I always wanted to build something similar but, dealing with ObjectAnimators, Interpolators and a lot of Maths and Physics didn’t make the things easy.

When the Airbnb Engineering Team open-sourced Lottie, the possibility to easily implement an animation created by the designer was too good to be true, and yet it was real: the first experiments with easy animations worked seamlessly.

Since then we have used Lottie a lot at Yoyo Wallet for both easy and complex animations.

What is Lottie?

Lottie is a library, available for Android, iOS and the web, that renders animations created in After Effects and exported as JSON files through a plugin called Bodymovin.
The resulted JSON is a collection of layers with different elements that define what will be drawn (shape, colour, images etc.).

http://airbnb.io/lottie/

Adding an Animation

The official documentation is very clear on how to display a Lottie animation in an Android App, just add a LottieAnimationView into your layout and reference your JSON with app:lottie_rawRes.The JSON has to be in the res/raw folder.

Until the version 2.3.0, the only way to add an animation was through the attribute app:lottie_fileName for JSON in the assets folder, but this method doesn’t provide any compile-time check so is strongly recommended to use app:lottie_rawRes

To play the animation you can either use the attribute app:lottie_autoPlay="true" so that the animation will start as soon as the view has been created, or programmatically with

lottie_animation.playAnimation()

It’s also possible to attach listeners to control the start, stop or the progress of the animation like addAnimatorListener() or addAnimatorUpdateListener().

An interesting option is not to store the animation in your APK but to provide an URL. This is very handy if you want to keep your APK size smaller or if you plan to change the animations quite often; in this case, you don’t have to release a new version of your App.

There’s no need to use an asynchronous task to make the call because Lottie uses a FutureTask to fetch the JSON; on top of that the result is stored in a cache on disk so, if the same URL is called multiple times the cached composition is returned. This method can be used to fetch the JSON in advance, eg. when the app is resumed if it’s likely that the animation is going to be displayed.

Of course, dealing with a network request at runtime poses some threats so it’s a good practice to check for errors. The basic implementation suggested in the official documentation is very straightforward:

lottie_animation.setAnimationFromUrl(animationUrl)

however, if Lottie fails to parse the JSON there is no way to catch the error, potentially crashing your App.

The best way to deal with an animation retrieved from an URL is to use a LottieCompositionFactory at which you can attach a FailureListener:

val lottieCompositionLottieTask = 
LottieCompositionFactory.fromUrl(this, animationUrl)
lottieCompositionLottieTask.addListener { result ->
my_lottie_animation_view.setComposition(result) }
lottieCompositionLottieTask.addFailureListener {
Log.e("Lottie", it.message) }

It’s also possible to provide to Lottie a zip file, either storing it in the App (in the assets folder) or through an URL (the method to use is the same as above). Lottie will unzip it and store it in the cache.

Changing an Animation programmatically

What if we want to change some properties of an animation like the colours?

As I explained, every composition is made of layers that contain elements and any element has a name that can be accessed through the KeyPath class.

The KeyPath class receives a list of strings, the names of the layers that let you navigate the hierarchy os the composition. It’s possible to use a wildcard to get multiple elements.

To understand how the composition is structured, instead of opening the JSON file and scrolling through all the layers, it’s possible to get the full hierarchy with 3 simple lines of code:

lottie_animation.addLottieOnCompositionLoadedListener {
lottie_animation.resolveKeyPath(KeyPath("**")).forEach {
Log.d("keypath", it.keysToString())
}
}

Worth noting that I used a listener to access the composition. This is a good practice because the view might not be drawn yet by the time we’re trying to get it, especially if we’re in the onCreate()of an Activity.

For these examples, I used a real animation that we display in the Yoyo App as a transaction confirmation.

The original animation

The result of the resolveKeyPath()is this:

keypath: [tick-parent]
keypath: [Tick]
keypath: [Tick, Group 1]
keypath: [Tick, Group 1, Stroke 1]
keypath: [Circle]
keypath: [Circle, Group 1]
keypath: [Circle, Group 1, Stroke 1]

So it’s clear that we have two main elements, the Tick and the Circle.

To change the colour of the Tick element we have to apply a different colour filter to the Stroke 1 element and we can achieve it using the addValueCallback method, that requires the KeyPath that specifies the element (or the elements) we want to change, the Property we want to change and a LottieValueCallback that, thanks to Kotlin, we can replace with a lambda:

lottie_animation.addValueCallback(
KeyPath("Tick", "Group 1", "Stroke 1"),
LottieProperty.COLOR_FILTER
) { PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.SRC_ATOP) }

and this is the result:

Tick changed to Black

Similar to the colour, if we want to change the opacity of the tick it’s possible to use the relative property:

lottie_animation.addValueCallback(
KeyPath("Tick", "Group 1", "Stroke 1"),
LottieProperty.OPACITY
) { 50 }
Opacity changed to 50

A list of all the properties that is possible to manipulate can be found here or in the LottieProperty class, where you can see all the accepted values per each property.

--

--