product & design

# Whole Lottie Love

I have to admit, when Lottie was initially announced by Airbnb I didn’t pay too much attention. I just skimmed the Github page without realising its true potential. Fast forward a few months to a project where we had to implement a hero animation in an app and Lottie popped into my head. So I had another look and boy, was I in for a surprise.

To quickly summarise Lottie, it’s essentially a view that can play almost any animation created in After Effects. The steps are easy: you make your animations in After Effects, export it into a JSON file with a plugin called bodymovin, add that file to your app and tell Lottie to play it. Super easy and super fast.

Okay, that’s cool, but why would you use Lottie? Apart from being able to reproduce intricate animations, the best thing about Lottie is that it recreates these animations on your app as vector layers, so they can scale across multiple screen sizes. And don’t forget that it’s all coming from a minuscule JSON file. So you can get rid of bulky drawables and complicated code and see even better results.

Let’s take a look at some major use cases of Lottie:
1. Big sparkly hero animations
2. Micro interactions eg icons animating on touch or other triggers
3. User-controlled UI elements - my personal favourite, more on this later.

Let’s go through each one of those use-cases, and then follow up with some guidelines on how to design Lottie animations for specific scenarios. You can expect demos and eye-candy along the way (all the gifs in this post are screen recordings from an Android emulator). Let’s go!

## Hero Animations

This is the most basic form of a Lottie animation. Let’s go through its setup starting with After Effects.

First thing you have to do is… wait for it… create the animation on After Effects. Or ask your designer to do it. You can then export it through the bodymovin plugin into a JSON file.

Now let’s jump into Android Studio and drop it into the assets folder of your project. If you don’t have an assets folder yet, make sure you add it to the root of the relevant sourceset (e.g., "src/main").

If Lottie isn’t set up yet, just add it normally as a dependency. In order to add the animation, use a LottieAnimationView in your layout and link it to the JSON file you just added to your asset folder, like so:

<com.airbnb.lottie.LottieAnimationView
android:id="@+id/animation_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:lottie_fileName="hero.json"
app:lottie_loop="false"
app:lottie_autoPlay="true"/>


There are a few attributes to note here:
1. lottie_fileName is obviously the name of the JSON file
2. lottie_loop will make your animation loop (wow)
3. lottie_autoPlay will make your animation start playing automatically when your layout is created (double wow)

Try to use wrap_content as your LottieAnimationView’s width and height. It seems like the view gets clipped in unpredictable ways when setting specific dimensions but it will always scale proportionally. The designer has to make sure the animation is designed with the correct dimensions before exporting the animation.

## Micro interactions

These are the animations that make your app feel hand-crafted and premium. You definitely don’t want to miss these. Think of icons that react to your touch, morphing shapes, task success indicators, loading loops, you name it.

There have been some tools emerging that use default Android APIs to recreate these animations such as ShapeShifter, although personally I would prefer to use Lottie as it’s much simpler to use and allows more complex animations.

These are implemented the same way as hero animations, except maybe you’d want them to start animating on a specific trigger. That’s easily done by calling lottieView.playAnimation();

Lottie also provides a good set of animation listeners, so you can swap JSON files, start them over, stop at a specific point or whatever you like.

lottieView.addAnimatorListener(new Animator.AnimatorListener() {

@Override
public void onAnimationStart(Animator animation) {}

@Override
public void onAnimationEnd(Animator animation) {}

@Override
public void onAnimationCancel(Animator animation) {}

@Override
public void onAnimationRepeat(Animator animation) {}
}
});


## User-controlled UI elements

My favourite part of Lottie is the method called .setProgress(float). Let me tell you why this is awesome. Views such as ViewPagers, BottomSheets, ScrollViews often offer an offset value that tells you how much the user has scrolled. How awesome would it be if you could run a certain animation based on the user’s amount of scrolling? Let me show you an example.

What we’re doing there is simply setting the progress of the animation based on the amount of scroll. If the user swipes forward, the animation goes forward. If the user swipes backwards, the animation will follow. It's all synchronised with the user interactions.

Let’s dive in a little deeper and separate the animation in five parts, one for each view of the ViewPager (yes, there are 5 pages in the animation above). One option is to create five different JSON files and swap them when the user reaches the limit of each page. Or, if you want to be super cool, progress the animation by 1/5 on each page. The following code will allow you to do just that:

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener(){
@Override
public void onPageScrolled(int position,
float positionOffset,
int positionOffsetPixels) {

lottieView.setProgress((position * (1f / PAGE_COUNT)) + (positionOffset * (1f / PAGE_COUNT)));
}
...
});


And this applies for BottomSheets, ScrollViews, PullToRefresh views, basically anything that gives you an offset value.

You don’t have to worry about frame rate for these animations, because even though the animation you’ve created on After Effects has a specific frame rate, Lottie creates each part of the animation on the fly. So your animation won’t appear choppy. Think of it as an SVG format for animations. There are a few things to keep in mind when creating the animation in After Effects. More on that below.

As the number of pages increases, your animation will likely begin to get choppy as the progress is a float and has limited resolution.

## Miscellaneous

Let’s talk about other useful things that Lottie allows you to do.

### Dynamic colouring

If your branding includes multiple colouring which you have to apply to your animations, or if it’s something user generated, you don’t have to create an animation for each one of those colours. Instead, Lottie offers a colour filter API, which you can use to set a colour to your animation in real-time. Note that this is not the same as ImageView#setColorFilter() which is also available because LottieAnimationView inherits from ImageView.

lottieView.addColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_TOP));


If you're planning to dynamically tint your animation or some of its layers, make sure you draw them in a solid colour such as black or white, for optimal results.

### Dynamic duration & interpolation

You might come across a scenario where you have to set the duration (and/or the interpolation) of your animation in code. You can do that by setting up a ValueAnimator which will run through 0 to your desired time using an interpolator, and in continuation, setting its value to the progress of your Lottie animation.

ValueAnimator valueAnimator =  ValueAnimator.ofFloat(0f, 1f);
valueAnimator.setDuration(300);
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
@Override
public void onAnimationUpdate(ValueAnimator animation) {
lottieView.setProgress(animation.getAnimatedFraction());
}
});
valueAnimator.start();


### Images from asset folder & JSON files on-the-go

In the "Loading" animation shown above, the lettering used is not a vector image but a png. You are able to images in your Lottie animation file, you can do so by adding them in your assets file and telling Lottie where to find them.

lottieView.setImageAssetsFolder("images");


And you don’t even have to keep your JSON files locally. If you need them to be dynamic, be it for A/B testing or if you’re frequently updating them, you can choose to download them.

Cancellable compositionCancellable = LottieComposition.Factory.fromJson(getResources(), jsonObject, (composition) -> {
lottieView.setComposition(composition);
lottieView.playAnimation();
}


## Design considerations

We mentioned that everything Lottie draws is a vector, right? It’s a good idea as a designer to start drawing your animations in Illustrator. It integrates seamlessly with After Effects, which allows quick iteration.

The size of your animation has to be in 1x (as you should be designing), but since Android screens vary it’s best to talk to your developer to find the best solution.

Your timings and interpolators will be exported and reproduced just fine, but if you’re doing user-controlled animations, you might not want to include interpolations in your animations. Since they will run based on the user scrolling, the interpolations will be transferred from the offset value to your animation. This doesn’t mean that you shouldn’t make use of interpolators in such scenarios. If that’s what you’re going after, by all means go ahead. What you should expect is the animation to run normally, it just won’t be synced to the user’s interaction.

## Conclusion

By now you might have realised that the best thing Lottie has to offer is easy reproduction of your After Effects animations with full control over their appearance.

What does this mean for us? It means that we have much more freedom to create sparkles for our app with minimal work from a development perspective. It’s super fast and easy to iterate these animations, as you only have to provide a new JSON file for the developers. This also means that apps can be greatly reduced in size, as there’s no need for drawables in all the different DPI buckets.

Check out the source .aep file of the animations showcased above here.
I'd love to see your cool Lottie designs and implementations. Feel free to tag me or drop me a line at @BashaChris on Twitter! 👍