This article is published by the Cloud + community

Author: paulzeng

**Lottie is an open source Airbnb animation library for iOS, Android and React Native. It can realize very complex animations and is extremely easy to use. It is worth a try.

A list,

Lottie is an open source animation library of Airbnb for iOS, Android and React Native, which can analyze animations exported by Adobe After Effects and enable Native apps to use these animations as static materials to achieve perfect animation Effects.

Now use the platform of native code implements a complex set of animation is a very difficult and time consuming, we need to load for different size of the screen to different material resources, also need to write a lot of difficult to maintain the code, and Lottie can do the same animation files on different platforms to achieve the same effect, greatly reduce development time, Different animation, only need to set up different animation files, greatly reduce development and maintenance costs.

Official renderings:

Two, how to use

Lottie supports multiple platforms, using the same JSON animation file to achieve the same effect on different platforms.

Android is implemented through Lottie-Android, an open source project of Airbnb, with minimum API 16 support.

IOS is realized through Lottie-ios, an open source project of Airbnb, with minimum support for IOS 7.

React Native, implemented through Airbnb’s open source project Lottie-React – Native;

Use Lottie on Android as an example

1. Download Lottie

Add dependencies to your project’s build.gradle file

dependencies {  
  compile 'com. Reality. The android: Lottie: 2.1.0'
}
Copy the code

2. Add the animation file exported by Adobe After Effects

Lottie reads Assets by default. We need to save the animation file react. Json in app/ SRC /main/ Assets. (The file is relatively large, only part of the content is shown, file link)

{
    "v": "4.6.0"."fr": 29.9700012207031."ip": 0."op": 141.000005743048."w": 800."h": 800."ddd": 0."assets": []."layers": [{"ddd": 0."ind": 0."ty": 4."nm": "center_circle"."ks": {... },"ao": 0."shapes": [...]. ."ip": 0."op": 900.000036657751."st": 0."bm": 0."sr": 1}, {... }, {... }, {... }}]Copy the code

3. Use Lottie

Add Lottie’s LottieAnimationView control directly to the layout file to display the React logo animation

<com.airbnb.lottie.LottieAnimationView
        android:id="@+id/animation_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:lottie_fileName="react.json"
        app:lottie_loop="true"
        app:lottie_autoPlay="true" />
Copy the code

4. Introduce Lottie influence

(1) the compatibility

API 16 is the lowest supported version of Lottie, with lower versions requiring degraded animations or no animations

(2) the installation package

Impact study Before using After using conclusion
Methods the number 144807 145891 Add 1084 methods
Installation package size 41969KB 42037KB Increase 68 KB

This is the test data of the release package of Quanmin Kge. Lottie itself has a large number of methods, and there are risks of exceeding the number of methods and too large installation package, so the business can evaluate by itself

Note: LottieAnimationView inherits from V7 AppCompatImageView, need to introduce V7 compatible package, according to business needs, can introduce Lottie source, let LottieAnimationView inherit and ImageView, do not need to introduce V7 compatible package, Installation size can be reduced.

3. Use tips

1. Load the SDCard animation file

StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new FileReader(new File(JSON_PATH + "react.json")));
String content = null;
while((content = bufferedReader.readLine()) ! =null){
    stringBuilder.append(content);
}
JSONObject jsonObject = new JSONObject(stringBuilder.toString());
animationView.setAnimation(jsonObject);
animationView.loop(true);
animationView.playAnimation();
Copy the code

2. Load the SDCard image

animationView.setImageAssetDelegate(new ImageAssetDelegate() {
    @Override
    public Bitmap fetchBitmap(LottieImageAsset asset) {
        try {
            FileInputStream fileInputStream = new FileInputStream(IMAGE_PATH + asset.getFileName());
            return BitmapFactory.decodeStream(fileInputStream);  /// Turn the stream into a Bitmap
        } catch (Exception e) {
            Log.e(TAG, "", e);
        }
        return null; }});Copy the code

3. Load the SDCard font

animationView.setFontAssetDelegate(new FontAssetDelegate(){
    public Typeface fetchFont(String fontFamily) {
        Typeface customFont = Typeface.createFromFile(FONT_PATH + fontFamily);
        returncustomFont; }});Copy the code

4. Cache animations

/* * Lottie has two internal cache maps (strong reference cache and weak reference cache). After the animation file is loaded, the animation will be cached according to the set cache policy for next use. * /
animationView.setAnimation(animation, LottieAnimationView.CacheStrategy.Strong);    / / cache

animationView.setAnimation(animation, LottieAnimationView.CacheStrategy.Weak);      / / cache
Copy the code

Iv. Implementation principle of Lottie

Designers use multiple layers to represent a complex image, with each layer showing part of the content. The content in the layer can also be broken down into multiple elements. After splitting the elements, you can animate the layer or the elements in the layer by translation, rotation, contraction, etc.

The resource used by Lottie is to convert aEP animation project files generated by Adobe After Effects (AE) into generic JSON format description files using BodyMovin (the BodyMovin plugin itself is an open source library for rendering various AE Effects on web pages). Lottie is responsible for parsing the animation data, calculating the state of each animation at a point in time, and accurately drawing it onto the screen.

Exported JSON animation description file:

{
    "v": "4.6.0"."fr": 29.9700012207031."ip": 0."op": 141.000005743048."w": 800."h": 800."ddd": 0."assets": []."layers": [{...},]}Copy the code

Lottie main class diagram:

Graph: lottie_class

Lottie externally exposes the interface through the control LottieAnimationView to control animation.

LottieAnimationView inherits from the ImageView and is displayed on the canvas at the current time. There are two key classes: LottieComposition, which parses json description files and converts the JSON content into Java data objects; LottieDrawable is responsible for drawing, drawing the data object converted into LottieComposition into a Drawable and displaying it on the View. The order is as follows:

1. Parse the JSON file

LottieComposition is responsible for parsing JSON files and mapping the data to Java objects.

(1) Parse the external structure of JSON

LottieComposition encapsulates the information of the entire animation, including the animation size, animation duration, frame rate, images used, fonts, layers, and so on.

Json external structure

{
    "v": "4.6.0"./ / bodymovin version
    "fr": 29.9700012207031./ / frame rate
    "ip": 0.// Start keyframe
    "op": 141.000005743048.// End the keyframe
    "w": 800.// Animation width
    "h": 800.// Animation height
    "ddd": 0."assets": [...].// Resource information
    "layers": [...].// Layer information
}
// Parse the json source code
static LottieComposition fromJsonSync(Resources res, JSONObject json) {
      Rect bounds = null;
      float scale = res.getDisplayMetrics().density;
      int width = json.optInt("w".- 1);
      int height = json.optInt("h".- 1);

      if(width ! =- 1&& height ! =- 1) {
        int scaledWidth = (int) (width * scale);
        int scaledHeight = (int) (height * scale);
        bounds = new Rect(0.0, scaledWidth, scaledHeight);
      }

      long startFrame = json.optLong("ip".0);
      long endFrame = json.optLong("op".0);
      float frameRate = (float) json.optDouble("fr".0);
      String version = json.optString("v");
      String[] versions = version.split("[the]");
      int major = Integer.parseInt(versions[0]);
      int minor = Integer.parseInt(versions[1]);
      int patch = Integer.parseInt(versions[2]);
      LottieComposition composition = new LottieComposition(
          bounds, startFrame, endFrame, frameRate, scale, major, minor, patch);
      JSONArray assetsJson = json.optJSONArray("assets");
      parseImages(assetsJson, composition); // Parse the image
      parsePrecomps(assetsJson, composition);
      parseFonts(json.optJSONObject("fonts"), composition); // Parse the font
      parseChars(json.optJSONArray("chars"), composition);  // Parse characters
      parseLayers(json, composition);   // Parse the layer
      return composition;
    }
Copy the code

(2) Analyze picture resources

The LottieImageAsset class encapsulates image information"assets": [                 // Resource information
    {                       // The first image
        "id": "image_0"./ / photo id
        "w": 58.// Image width
        "h": 31.// Image height
        "u": "images/".// Image path
        "p": "img_0.png"    // Image name}, {... }// the NTH image
]
static LottieImageAsset newInstance(JSONObject imageJson) {
    return new LottieImageAsset(imageJson.optInt("w"), imageJson.optInt("h"), imageJson.optString("id"),
          imageJson.optString("p"));
}
Copy the code

(3) Parse layers

Layer encapsulates Layer information. Currently Lottie only supports PreComp, Solid, Image, Null, Shape, and Text layers.

"layers": [                 // Layer information
    {                       // The first layer animation
        "ddd": 0."ind": 0.//layer id Indicates the layer ID
        "ty": 4.// Layer type
        "nm": "center_circle"."ks": {... },/ / animation
        "ao": 0."shapes": [...]. ."ip": 0.//inFrame The layer start keyframe
        "op": 90.//outFrame This layer ends the keyframe
        "st": 0./ / startFrame began
        "bm": 0."sr": 1}, {... }// Layer N animation
]
Copy the code

2. How to get moving

Lottie Sequence diagram:

Using property animation to control progress, each progress change is notified to each layer, triggering LottieAnimationView redraw.

(1) Use attribute animation to calculate progress

The property animation is used here to generate an interpolation between 0 and 1, and the current animation progress is set according to the interpolation.

The code is as follows:

public LottieDrawable() {
    animator.setRepeatCount(0);
    animator.setInterpolator(new LinearInterpolator());
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            if (systemAnimationsAreDisabled) {
                animator.cancel();
                setProgress(1f);
            } else{ setProgress((float) animation.getAnimatedValue()); }}}); }Copy the code

(2) Pass the progress to each layer through CompositionLayer

@Override
public void setProgress(@FloatRange(from = 0f, to = 1f) float progress) {
    super.setProgress(progress);
    if(timeRemapping ! =null) {
        long duration = lottieDrawable.getComposition().getDuration();
        long remappedTime = (long) (timeRemapping.getValue() * 1000);
        progress = remappedTime / (float) duration;
    }
    if(layerModel.getTimeStretch() ! =0) {
        progress /= layerModel.getTimeStretch();
    }
    progress -= layerModel.getStartProgress();
    for (int i = layers.size() - 1; i >= 0; i--) { layers.get(i).setProgress(progress); }}Copy the code

(3) Notify progress changes

  void setProgress(@FloatRange(from = 0f, to = 1f) float progress) {
    if (progress < getStartDelayProgress()) {
      progress = 0f;
    } else if (progress > getEndProgress()) {
      progress = 1f;
    }

    if (progress == this.progress) {
      return;
    }
    this.progress = progress;

    for (int i = 0; i < listeners.size(); i++) { listeners.get(i).onValueChanged(); }}Copy the code

(4) Finally callback to LottieAnimationView’s invalidateDrawable

@Override
public void invalidateDrawable(@NonNull Drawable dr) {
    if (getDrawable() == lottieDrawable) {
      // We always want to invalidate the root drawable so it redraws the whole drawable.
      // Eventually it would be great to be able to invalidate just the changed region.
        super.invalidateDrawable(lottieDrawable);
    } else {
      // Otherwise work as regular ImageView
        super.invalidateDrawable(dr); }}Copy the code

(5) Finally trigger Lottie Edrawable redraw

@Override
public void draw(@NonNull Canvas canvas) {
    ...
    matrix.reset();
    matrix.preScale(scale, scale);
    compositionLayer.draw(canvas, matrix, alpha);   // All layer draw methods are called here
    if(hasExtraScale) { canvas.restore(); }}Copy the code

Five, performance,

1. Official notes

Without masks and Mattes, performance and memory are great, no bitmap is created, and most operations are simple Cavas drawing.

If mattes exist, 2 or 3 bitmaps will be created. Bitmaps are created when the animation is loaded into the window and reclaimed when the window is deleted. Therefore, it is not suitable to use animation containing Mattes or mask in RecyclerView, otherwise it will cause bitmap jitter. In addition to memory jitter, the necessary bitmap.erasecolor () and Canvas.drawbitmap () in mattes and Masks also reduce animation performance. For simple animations, the performance is not obvious in practical use.

If the use of animation in the list, it is recommended to use the cache LottieAnimationView. SetAnimation (String, CacheStrategy).

2. Property animation and Lottie animation comparison

The performance comparison below is for animations of individual gifts within karaoke songs

Attribute animation Lottie uses hardware acceleration Lottie does not use hardware acceleration
Frame rate
content
CPU

Without hardware acceleration enabled, Lottie animation has worse frame rate, memory, and CPU than attribute animation, but with hardware acceleration enabled, performance is similar.

3, hardware acceleration is not enabled, Lottie animation size frame rate comparison

0.12 times 1 times

The main time is in the DRAW method, the smaller the drawing area, the smaller the time

Six, karaoke song available scenes

1. Feature guidance video

There will be a video boot animation for the first startup of each big version of Kk, and each time there will be a balance between clarity and file size. Finally, a boot video of about 3-4M is exported. Using Lottie can improve the animation clarity and reduce the installation package size

2. Loading animation

3. Gift animation

This is the gift panel of National KARAOKE. There are a large number of gift animations inside, each of which is different. During the animation process, there are a large number of rotation, transparency and size changes, which need to be realized by property animation, which is very troublesome and the code maintainability is poor. There are several advantages to using Lottie:

1, 100% achieve the design effect

2. The amount of client code is very small and easy to maintain

3. Dynamically configure animation styles for each animation (load different JSON)

4, all animation can be dynamically configured, animation configuration files, materials can be loaded from the Internet

4. The rap

The rap function of karaoke requires the lyrics to be displayed in accordance with specific animation, which involves special effects such as amplification, contraction and rotation of lyrics. When it is implemented, the lyrics are drawn on the canvas according to the current time, and finally merged with the sound to generate a MV video. As a result, the animation cannot be particularly complicated and has certain rules.

If you use Lottie, you can export the effects to a JSON animation file. The client loads the animation file, loops through the progress, reads each frame, and then blends it with the sound to generate an MV.

Advantage:

1. Rich animation

2. Less code

3. Use typefaces exported by design

code

animationView.setProgress(progress);        // Set the current progress
animationView.buildDrawingCache();          // Force the cache to draw data
Bitmap image = animationView.getDrawingCache(); // Get the current drawing data
Copy the code

Seven,

1. The disadvantage

(1) Performance is not good enough — some animation effects, memory and performance are not good enough; Frame rates are lower when displaying large animations compared to property animations

Advantage of 2.

(1) High development efficiency — simple code implementation, convenient replacement of animation, easy debugging and maintenance.

(2) Diversity of data sources — animation resources can be loaded from assets, SDcard and network, and can be dynamically updated without issuing versions

(3) Cross-platform — Export an animation description file for android,ios, and React Native

Lottie is easy to use, easy to get started, and well worth trying out.

Viii. Reference materials

1.GitHub – airbnb/lottie-android: Render After Effects animations natively on Android and iOS

2. A Brief analysis of the use and principle of Lottie – Color pen Senior – CSDN blog

3. From JSON files to cool animation -Lottie implementation ideas and source code analysis – simple book

4.Most Popular – LottieFiles

This article has been published by Tencent Cloud + community authorized by the author

For more fresh technology dry goods, you can follow usTencent Cloud technology community – Cloud Plus community official number and Zhihu organization number