GitHub:https://github.com/airbnb/lottie-android
Getting Started
Add the dependency to your project build.gradle
file:
dependencies {
...
implementation "com.airbnb.android:lottie:$lottieVersion"
...
}
The latest version is:
Sample App
You can build the sample app yourself or download it from the Play Store. The sample app includes some built in animations but also allows you to load an animation from internal storage or from a url.
Core Classes
LottieAnimationView
extends ImageView and is the default and simplest way to load a Lottie animation.LottieDrawable
has most of the same APIs as LottieAnimationView but you can use it on any View you want.LottieComposition
is the stateless model representation of an animation. This file is safe to cache for as long as you need and can be freely reused across drawables/views.LottieCompositionFactory
allows you to create a LottieComposition from a number of inputs. This is what thesetAnimation(...)
APIs onLottieDrawable
andLottieAnimationView
use under the hood. The factory methods share the same cache with those classes as well.
Loading an Animation
Lottie can load animations from:
- A json animation in
src/main/res/raw
. - A json file in
src/main/assets
. - A zip file in
src/main/assets
. See images docs for more info. - A dotLottie file in
src/main/assets
. - A url to a json or zip file.
- A json string. The source can be from anything including your own network stack.
- An InputStream to either a json file or a zip file.
From XML
The simplest way to use it is with LottieAnimationView:
It is recommended to use lottie_rawRes
because you can use static references to your animation through R
instead of just using string names.
From res/raw (lottie_rawRes
) or assets/ (lottie_fileName
)
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/animation_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:lottie_rawRes="@raw/hello_world"
// or
app:lottie_fileName="hello_world.json"
// Loop indefinitely
app:lottie_loop="true"
// Start playing as soon as the animation is loaded
app:lottie_autoPlay="true" />
Programmatically
LottieAnimationView
, LottieDrawable
, and LottieCompositionFactory
each has methods for the corresponding locations.
Note: to correctly load dark mode (-night
) resources, make sure you pass Activity
as a context where possible (instead of e.g. the application context). The Activity
won’t be leaked.
Caching Animations
All Lottie animations are cached with a LRU cache by default. Default cache keys will be created for animations loaded from res/raw/
or assets/
. Other APIs require setting a cache key.
If you fire multiple animation requests for the same animation in parallel such as a wishlist heart in a RecyclerView, subsequent requests will join the existing task so it only gets parsed once.
Global Configuration
Lottie has some global configuration options. None are required by default but it can be used to:
- Use your own network stack instead of Lottie’s built in one when loading animations from the network.
- Provide your own cache directories for animation fetched from the network instead of using Lottie’s default one (
cacheDir/lottie_network_cache
). - Enable systrace makers for debugging.
- Disable Lottie’s network cache completely if you want to implement custom network fetcher-level caching strategy.
To set it up, somewhere during your application initialization, include:
Lottie.initialize(
LottieConfig.Builder()
.setEnableSystraceMarkers(true)
.setNetworkFetcher(...)
.setNetworkCacheDir(...)
.setEnableNetworkCache(false)
)
Animation Listeners
You can control the animation or add listeners:
animationView.addAnimatorUpdateListener { animation ->
}
animationView.addAnimatorListener(...)
animationView.addPauseListener {
}
In the update listener callback:
animation.getAnimatedValue()
will return the progress of the animation regardless of the currently set min/max frame [0,1].
animation.getAnimatedFraction()
will return the progress of the animation taking into account the set min/max frame [minFrame,maxFrame].
Failure Listener
Set a default failure listener that will be called if any of the setAnimation APIs fail for any reason. This can be used to replace the default behavior. The default behavior will log any network errors and rethrow all other exceptions.
If you are loading an animation from the network, errors may occur if your user has no internet. You can use this listener to retry the download or you can have it default to an error drawable with setFallbackResource(int)
. Unless you are using setAnimationFromUrl(String)
, errors are unexpected.
Set the listener to null
to revert to the default behavior.
Custom animators
Although playAnimation()
is sufficient for the vast majority of use cases, you can call setProgress(...)
in the update callback for your own animator. This can be useful to tie an animation to something like a gesture, download progress, or scroll position.
// Custom animation speed or duration.
val animator = ValueAnimator.ofFloat(0f, 1f)
animator.addUpdateListener {
animationView.setProgress(animation.animatedValue)
}
animator.start()
Looping
Lottie support advanced looping functionality that mirrors ValueAnimator
. As such, you can call setRepeatMode(...)
or setRepeatCount(...)
as you would on a ValueAnimator
You can also enable looping from xml with lottie_loop="true"
You can loop a specific part of an animation by using setMinFrame
, setMaxFrame
, or setMinAndMaxFrame
. There are multiple versions of each that take frame, progress (from 0.0 to 1.0) or a marker name (specified in After Effects).
Animation Size (px vs dp)
Lottie converts all px values in After Effects to dps on device so that everything is rendered at the same size across devices. This means that instead of making an animation in After Effects that is 1920x1080, it should be more like 411x731px in After Effects which roughly corresponds to the dp screen size of most phones today.
However, if your animation isn’t the perfect size, you have two options:
Dynamic Properties
You can update properties dynamically at runtime. This can be used for a variety of purposes such as:
- Theming (day and night or arbitrary themes).
- Responding to events such as an error or a success.
- Animating a single part of an animation in response to an event.
- Responding to view sizes or other values not known at design time.
Understanding After Effects
To understand how to change animation properties in Lottie, you should first understand how animation properties are stored in Lottie.
Animation properties are stored in a data tree that mimics the information hierarchy of After Effects. In After Effects a Composition
is a collection of Layers
that each have their own timelines. Layer
objects have string names, and their contents can be an image, shape layers, fills, strokes, or just about anything that is drawable. Each object in After Effects has a name. Lottie can find these objects and properties by their name using a KeyPath
.
Usage
To update a property at runtime, you need 3 things:
- KeyPath
- LottieProperty
- LottieValueCallback
KeyPath
A KeyPath is used to target a specific content or a set of contents that will be updated. A KeyPath is specified by a list of strings that correspond to the hierarchy of After Effects contents in the original animation.
KeyPaths can include the specific name of the contents or wildcards:
- Wildcard
*
- Wildcards match any single content name in its position in the keypath.
- Globstar
**
- Globstars match zero or more layers.
KeyPath resolution
KeyPaths have the ability to store an internal reference to the content that they resolve to. When you create a new KeyPath object, it will be unresolved. LottieDrawable and LottieAnimationView has a resolveKeyPath()
method that takes a KeyPath and returns a list of zero or more resolved KeyPaths that each resolve to a single piece of content and are internally resolved. This can be used to discover the structure of your animation if you don’t know it. To do so, in a development environment, resolve new KeyPath("**")
and log the returned list. However, you shouldn’t use **
by itself with a ValueCallback because it will be applied to every single piece of content in your animation. If you resolve your KeyPaths and want to subsequently add a value callback, use the KeyPaths returned from that method because they will be internally resolved and won’t have to do a tree walk to find the content again.
See the documentation for KeyPath
for more information.
LottieProperty
LottieProperty is an enumeration of properties that can be set. They correspond to the animatable value in After Effects and the available properties are listed above and in the documentation for LottieProperty
ValueCallback
The ValueCallback is what gets called every time the animation is rendered. The callback provides:
- Start frame of the current keyframe.
- End frame of the current keyframe.
- Start value of the current keyframe.
- End value of the current keyframe.
- Progress from 0 to 1 in the current keyframe without any time interpolation.
- Progress in the current keyframe with the keyframe’s interpolator applied.
- Progress in the overall animation from 0 to 1.
There are also some helper ValueCallback
subclasses such as LottieStaticValueCallback
that takes a single value of the correct type in its constructor and will always return that. Think of it as a fire and forget value. There is also a relative value callback that offsets the real animation value by a specified amount.
ValueCallback classes
- LottieValueCallback: Either set a static value in the contructor or override getValue() to set the value on every frame.
- LottieRelativeTYPEValueCallback: Either set a static value in the constructor or override getOffset() to set a value taht will be applied as an offset to the actual animation value on each frame. TYPE is the same type as the LottieProperty parameter.
- LottieInterpolatedTYPEValue: Supply a start value, end value, and optional interpolator to have the value automatically interpolate across the entire animation. TYPE is the same type as the LottieProperty parameter.
Usage
animationView.addValueCallback(
KeyPath("Shape Layer", "Rectangle", "Fill"),
LottieProperty.COLOR,
{ Color.RED }
)
animationView.addValueCallback(
KeyPath("Shape Layer", "Rectangle", "Fill"),
LottieProperty.COLOR,
{ if (it.overallProgress < 0.5) Color.GREEN else Color.RED }
)
Animatable Properties
The following value can be modified:
Transform | Layer | Fill | Stroke | Ellipse | Polystar | Repeater | Image | Text |
---|---|---|---|---|---|---|---|---|
TRANSFORM_ANCHOR_POINT | TRANSFORM_ANCHOR_POINT | COLOR | STROKE_COLOR | ELLIPSE_SIZE | POLYSTAR_POINTS | REPEATER_COPIES | IMAGE | COLOR |
TRANSFORM_POSITION | TRANSFORM_POSITION | OPACITY | STROKE_WIDTH | POSITION | POLYSTAR_ROTATION | REPEATER_OFFSET | COLOR_FILTER | STROKE_COLOR |
TRANSFORM_OPACITY | TRANSFORM_OPACITY | COLOR_FILTER | COLOR_FILTER | POSITION | TRANSFORM_ROTATION | STROKE_WIDTH | ||
TRANSFORM_SCALE | TRANSFORM_SCALE | OPACITY | POLYSTAR_OUTER_RADIUS | TRANSFORM_START_OPACITY | TEXT_TRACKING | |||
TRANSFORM_ROTATION | TRANSFORM_ROTATION | POLYSTAR_OUTER_ROUNDEDNESS | TRANSFORM_END_OPACITY | TEXT_SIZE | ||||
TIME_REMAP (composition) | POLYSTAR_INNER_RADIUS | TYPEFACE | ||||||
TEXT |
Notable Properties
Time Remapping
Compositions and precomps (composition layers) have an a time remap proprty. If you set a value callback for time remapping, you control the progress of a specific layer. To do so, return the desired time value in seconds from your value callback.
Color Filters
The only animatable property that doesn’t map 1:1 to an After Effects property is the color filter property you can set on fill content. This can be used to set blend modes on layers. It will only apply to the color of that fill, not any overlapping content.
Images
Lottie is designed to work with vector shapes. Although Lottie supports rendering images, there are disadvantages to using them:
- The files are an order of magnitude larger than their equivalent vector animation.
- They get pixelated when scaled.
- They add complexity to the animation. Instead of one file, you have the json file plus all of the images.
A common cause of images in Lottie files is that bodymovin exports Illustrator layers from After Effects as images. If you think this might be the case, follow the instructions here.
Setting your images
You can set Lottie images in three ways:
src/assets
Put the images in a folder inside of src/assets
and don’t change the filenames of the images.
Then, tell Lottie to the assets folder where the images are stored by calling setImageAssetsFolder
on LottieAnimationView
or
LottieDrawable
with the relative folder inside of assets or with the app:lottie_imageAssetsFolder
attribute on your LottieAnimationView.
Again,make sure that the images that bodymovin exports are in that folder with their names unchanged (should be img_#).
Zip file
Alternatively, you can create a zip file with your json and images together. Lottie can unzip and read the contents. This can be done for local files or from a url.
Providing your own images
Sometimes, you don’t have the images bundled with the device. You may do this to save space in your apk or if you downloaded the animation from the network. To handle this case, you can use dynamic properties with LottieProperty.IMAGE
What is the impact of Lottie on APK size?
Very small:
- ~1600 methods.
- 287kb uncompressed.
Lottie vs Android Vector Drawable (AVD)
There are two ways to render After Effects animations:
- Export json with Bodymovin and play it with lottie-android.
- Export AndroidVectorDrawable xml with Bodymovin and play it using the Android SDK.
Pros of Lottie
- Supports a much larger set of After Effects features. See supported features for a full list.
- Manually set progress to hook up an animation to a gesture, event, etc.
- Download animations from the network.
- Dynamic playback speed.
- Masks are anti-aliased.
- Dynamically change the color of a specific part of an animations
Pros of AnimatedVectorDrawable
- Faster peformance due to the animation running on the RenderThread vs the main thread.
Performance
Masks and Mattes
Masks and mattes on android have the larges performance hit. Their performance hit is also proportional to the intersection bounds of the masked/matted layer and the mask/matte so the smaller the mask/matte, the less of a performance hit there will be.
On Android, if you are using masks or mattes, there will be a several X performance improvement when using hardware acceleration.
For debugging purposes, Lottie can outline all masks and mattes in your animation. To do that, just call setOutlineMasksAndMattes(true)
on your LottieAnimationView
or LottieDrawable
.
Hardware Acceleration
Lottie supports hardware acceleration but it is disabled out of the box. Read this article to learn more about hardware acceleration. It is disabled by default because it doesn’t support anti-aliasing, stroke caps (pre-API 18), and a few other things. In addition, depending on the animation, they may actually be less performant. Read this article to understand why.
If you are having performance issues with your animation, make sure to read the performance docs first. There is more information about how to benchmark and determine if your animation would benefit from hardware acceleration there.
Merge Paths
Merge paths are only supported on KitKat and above. There is also some performance overhead in using them because [Path.Op](https://developer.android.com/reference/android/graphics/Path.html#op(android.graphics.Path,%20android.graphics.Path.Op) can be slow. To prevent engineers from testing on new devices with merge paths enabled while shipping a broken experience to users on older phones, they are disabled by default. If your minSdk
is >=19 then you can enable then with enableMergePathsForKitKatAndAbove()
Render Graph
The Lottie sample app has a real time render graph that can be enabled from the menu in the top right. It also has guidelines for 16.66 and 33.333ms per frame which represent the maximum render time to hit 60fps and 30fps respectively.
Render Times Per Layer
The Lottie sample app also has a bottom sheet with the time it took each layer to render. To access it, click the render graph in the control bar and then tap “View render times per layer”.
If there are any layers that are particularly slow, try optimizing their shapes, eliminated masks, mattes, and merge paths where possible.
Troubleshooting
There may be times in which Lottie doesn’t render your animation correctly. After effects has an enormous number of features, not all of which are supported by Lottie. If an animation doesn’t look correct, run through the following steps before reporting an issue.
Check for Warnings
The Lottie for Android will automatically detect and report some errors. It doesn’t catch everything but will catch many common cases. You can either call getWarnings()
from your own code or open the animation in the Lottie sample app and see if warnings show up in the top right. If they do, tapping it will give you more information.
Check the supported features page.
Check the supported features page on this site to see if you are using anything that isn’t supported.
Debug
Try rendering individual parts of the animation to see which feature isn’t rendering correctly. See if you can narrow it down to a specific combination of shapes and effects or anything more specific than “it doesn’t look right”. If the issue should be supported and isn’t, file an issue on the appropriate lottie github page with a description and a zip of the aep file.
Missing merge paths
Merge paths are only available on KitKat and above so you must manually enable them using enableMergePathsForKitKatAndAbove()
Animation Clipping
Make sure you are using the latest version of Lottie.
Performance Testing
Performance and memory testing was aided by YourKit which provides powerful performance and memory profiling tools for Java.