Application summary of Lottie animation in the project
1. Background
Based on the high-frequency usage of lottie animation, this paper summarizes the use skills and precautions of lottie animation in the project, which is convenient for dealing with similar needs in the project in the future, rapid retrieval and application, and will be improved from time to time in the later stage. You are welcome to supplement and correct the deficiencies.
2. What is Lottie?
Lottie is an open source animation framework that supports Android, iOS, React Native, Web and Windows devices at the same time.
Users only need to use it first Adobe After Effects The software makes animation, and then passes the animation file Bodymovin When exported as json files, you can parse these json files through Lottie to realize animation.
Front end developers only need to get the json file given by the UI (dynamic effect) students to realize 100% restoration of dynamic effect, which is simple and efficient.
3. Lottie core class
Lottie provides a lottieanimation view for users to use. In fact, the core of Lottie is LottieDrawable, which carries all the drawing work. Lottieanimation view encapsulates LottieDrawable and adds some functions such as parsing.
- Lottieposition is the corresponding Model, which carries all the information.
- CompositionLayer is a collection of layers.
- ImageAssetBitmapManager is responsible for managing the image resources required for animation.
- Lottieanimation view is the default and easiest way for users to load Lottie animation (directly)
4. Use steps
Open source address: https://github.com/airbnb/lottie-android
- Add dependency
dependencies { implementation 'com.airbnb.android:lottie:$lottieVersion' }
Up to now, the latest version is: 4.2.1
- Use in layout xml:
<com.airbnb.lottie.LottieAnimationView android:id="@+id/lottieAnimationView" android:layout_width="wrap_content" android:layout_height="wrap_content" app:lottie_fileName="hello-world.json" app:lottie_loop="true" app:lottie_rawRes="@raw/heart" app:lottie_imageAssetsFolder="images" app:lottie_autoPlay="true"
Note: the app here is Lottie_ rawRes,app:lottie_ The two properties filename are the same.
In the above figure, @ raw/heart in xml is a json file, and Lottie is implemented by parsing json files.
LottieAnimationView animationView = ... animationView.setAnimation(R.raw.hello_world); // or animationView.setAnimation(R.raw.hello_world.json); animationView.playAnimation();
- Control animation add animation monitor
lottieAnimationView.addAnimatorUpdateListener((animation) -> { // Animation status monitoring callback }); lottieAnimationView.playAnimation(); // Play animation ... if (lottieAnimationView.isAnimating()) { // Animation is running } ... // Progress range 0 ~ 1f, set animation progress lottieAnimationView.setProgress(0.5f); ... // Customize the animation duration. Here, use the ValueAnimator value animation to update the progress of AnimationView in real time to control the animation duration. ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f) .setDuration(500); animator.addUpdateListener(animation -> { lottieAnimationView.setProgress(animation.getAnimatedValue()); }); animator.start(); // Start animation ... lottieAnimationView.cancelAnimation();// Cancel animation
Therefore, you can freely control the frequency of animation, the playback progress of animation, various states of animation, etc
- Common methods:
method | function |
---|---|
setAnimation(int) | Set the name of the json file to play the animation |
setAnimation(int, CacheStrategy) | Set json file resources and cache strategy for playing animation |
loop(boolean) | Sets whether the animation loops (false by default) |
setRepeatMode(int) | Sets the repetition mode of the animation (restart by default) |
setRepeatCount(int) | Sets the number of repetitions of the animation (default is - 1) |
lottie_cacheStrategy | Set the cache policy for animation (the default is weak) |
lottie_colorFilter | Sets the animated shading color (lowest priority) |
setScale(float) | Sets the scale of the animation (the default is 1f) |
setProgress(float) | Set the playback progress of the animation |
setImageAssetsFolder(String) | Set the image resource file address that the animation depends on |
playAnimation() | Play the animation from scratch |
pauseAnimation() | Pause animation |
resumeAnimation() | Continue playing animation from current position |
cancelAnimation() | Cancel animation playback |
- Monitor animation progress [0,1]
lottieAnimationView.addAnimatorUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { // Judge the end of animation loading if (valueAnimator.getAnimatedFraction() == 1f) { } } });
- Loop / play a part
lottieAnimationView.loop(true); // Play a part of the animation setMinFrame(...) setMaxFrame(...) setMinProgress(...) setMaxProgress(...) setMinAndMaxFrame(...) setMinAndMaxProgress(...)
4. Gets the duration of the animation
// For example, the duration of obtaining the animation (lottie_count_down) material given by the UI val lottieComposition: LottieComposition = LottieCompositionFactory.fromRawResSync( context, R.raw.lottie_count_down ).value!! Log.d(TAG, "lottieComposition.duration : ${lottieComposition.duration} ") // Get 6000ms
5. Precautions for use
1. Control the speed and time of Lottie animation execution
After Lottie animation is exported to JSON, the speed and duration of animation execution have been fixed. Therefore, if you want to modify these two parameters, in addition to bothering the designer to use After Effects to modify them again and then export them, you can also use ValueAniamtor with setProgress() method.
2. Lottie's cache strategy
There may be some frequently used animations in the application, such as loading animations and so on. To avoid the overhead of loading files and serializing each time, you can set a caching strategy on your animation. In setAnimation() APIs, the optional second parameter CacheStrategy can be used.
By default, Lottie will save weak references to animation, which should be sufficient for most cases.
However, if you are sure that an animation will be used frequently, change its caching policy to cachestrategy Strong;
Or if you are sure that an animation is large and will not be used often, change the cache strategy to cachestrategy None.
CacheStrategy can be in three forms: None, weak, and Strong to let lottieanimation view use Strong or weak references to load and parse animation. Weak or Strong indicates the strength of the combined GC references in the cache.
6. Use examples in projects
Demand scenario:
When the user plays the countdown video, the smooth dynamic effect of the horizontal progress bar is realized synchronously according to the length of the video played.
Development and implementation ideas:
According to the animation (count_down.json) material provided by the UI, calculate the playback progress and speed at different times.
<com.airbnb.lottie.LottieAnimationView android:id="@+id/lottieCountDownTime" android:layout_width="100dp" android:layout_height="100dp" android:layout_gravity="center" app:lottie_fileName="lottie/count_down.json" />
Key ideas:
var mRestPastTime = 0L private var countDownDuration: Long = 60L fun start() { lottieCountDownTime.removeUpdateListener(mRestLottieAnimatorUpdateListener) lottieCountDownTime.cancelAnimation() mRestPastTime = 0L lottieCountDownTime.apply { val lottieComposition: LottieComposition = LottieCompositionFactory.fromRawResSync( context, R.raw.lottie_count_down ).value!! mRestLottieAnimatorUpdateListener = ValueAnimator.AnimatorUpdateListener { animation -> mRestPastTime = (countDownDuration * animation.animatedFraction).toLong() Log.d(TAG, "lottieComposition.duration : ${lottieComposition.duration} ") // 5016ms countDownTime = countDownDuration - mRestPastTime val leftTime = (countDownTime / 1000).toString() Log.d(TAG, "leftTime:$leftTime ") // 59 ~ 0 s setRestTimeText(countDownDuration - mRestPastTime, false) if (animation.animatedFraction >= 1) { //Playback end processing } } setComposition(lottieComposition) progress = 0f //Core point: control the playback progress according to the duration speed = lottieComposition.duration / countDownDuration playAnimation() addAnimatorUpdateListener(mRestLottieAnimatorUpdateListener) } }
According to the above use examples, the dynamic effect of the horizontal progress bar given by the UI is realized, which is very smooth, and the sliding progress can correspond to the progress one by one according to different time lengths. In the countdown scene, if the user repeatedly pauses and starts the operation when playing the video, we have to deal with the problem of synchronization between the progress and the timing status. lottie animation is used here. You only need to call pause animation and resume animation.
Other implementation ideas 1:
If you use attribute animation to achieve, there may be different smooth or Caton situations.
Examples of using attribute Animation:
/** * Set the progress of ProgressBar (smooth growth) * @param progressBar progressBar * @param progressTo The value of 0 - 100 makes the smoothing effect smoother in 10 times of time */ private fun setProgressSmooth(progressBar: ProgressBar, progressTo: Int) { val animator = ObjectAnimator.ofInt( progressBar, "progress", progressBar.progress, progressTo * 10 ) animator?.apply { duration = 300 // Uniform drawing interpolator = LinearInterpolator() start() } }
<ProgressBar android:id="@+id/countDownPb" style="@android:style/Widget.ProgressBar.Horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:max="1000" android:progressDrawable="@drawable/pb_pd_bg" tools:progress="500" />
Note: Pb_ pd_ bg. Implementation of background map in XML
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Progress bar background color --> <item android:id="@android:id/background"> <shape> <solid android:color="@color/black" /> </shape> </item> <!-- Second progress bar --> <item android:id="@android:id/progress"> <clip> <shape> <solid android:color="@color/blue" /> </shape> </clip> </item> </layer-list>
Here, android:max="1000" is set to 1000. It should be noted that in normal development, we usually set it to 100. Here is a new idea. Zooming in 10 times when the progress is refreshed, combined with the linear interpolator feature of attribute animation, can basically achieve the effect of horizontal smoothness. However, when the user repeatedly pauses or resumes the countdown, due to the duration of attribute animation drawing time, it will not stop immediately, and there will be a sense of delay and pause.
Other development ideas 2:
You can use the idea of custom View to synchronize the progress when OnDraw refreshes. How to count down? If you don't want a smooth effect, you can 1s update the progress once,
If you want a smooth progress, update it once in 10ms. However, business logic such as suspension and resumption of countdown needs to be handled.
To sum up, two usage methods are summarized. In actual development, they are selected according to different usage scenarios. According to the current resource and dynamic efficiency requirements, lottile is the simplest and most efficient.
(I will further summarize later: the smooth progress in the round countdown, several ways to realize the countdown and the application of scenarios)
7. FQA
1, How to quickly preview a designer's lottie animation?
- UI designers provide Demo and dynamic Json+ HTML files. Click open the HTML file to preview.
- Online preview https://lottiefiles.com/private/animations After registering and logging in, directly put XX Drag the JSON dynamic file to the interface preview. The dynamic effect of some white may not be visible. It's best to confirm with the designer.
- Finally, preview in the code implementation.
2, Problem with loading carton
To be added
3, Set progress issues
setMinAndMaxProgress(0.5f, 1f)
After setting the progress: the speed here will accelerate
4, lottie animation size settings
Since the underlying layer of lottie is ImageView, it can only be solved by referring to similar properties.
If, set:
<com.airbnb.lottie.LottieAnimationView android:id="@+id/countDownPb" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitXY" app:lottie_fileName="lottie/lottie_horizontal_progress.json" />
lottie_ horizontal_ progress. The size in JSON may not be covered with match_parent: android:scaleType="fitXY"
Here, you need to pay attention to the adapter. If the dynamic effect given by the UI is designed according to the fixed size, do not set this property here, otherwise the position will be disordered.
8. Future direction
May replace lottie with PAG
Compare PAG and lottie from the decoding and rendering level
9. References
lottie-android : github.com/airbnb/lott...
Introducing Lottie: medium.com/airbnb-engi...
design-lottie: airbnb.design/lottie/
bodymovin: github.com/bodymovin/b...
Animation: Jump-through: medium.com/google-deve...