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.

Ii. Lottie animation file production

1. Have the designer create the animation using Adobe’s After Effects tool (which artists usually do).

2. Install a plugin called Bodymovin in After Effects. Download bodyMovin, unzip it and just need the file \build\extension\bodymovin. ZXP

3. Install the plugin manually. For Windows, download the ExMan Command Line tool and unzip it. Then copy the bodymovin. ZXP file from bodymovin-master\build\extension into the same folder.

4. Go to CMD and execute as system administrator. 5. Type CD C:/ExManCmd_win to go to the ExManCmd folder. 6. Then type exmancmd.exe /install bodymovin.zxp to complete

7. Enter the AE, can be found in the Windows/extentions/bodymovin plug-in, after open press Render is completed. A JSON file is generated in the Destination Folder directory of your choice. This JSON file describes the coordinates and movement of the key points of the animation.

3. How to use Lottie

Lottie supports multiple platforms, using the same JSON animation file to achieve the same effect on different platforms. Support Android, ios, front segment.

1. Rely on

Add dependencies to your project’s build.gradle file

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

2. Animation files

The first way is to save the animation file load. json in app/ SRC /main/assets. The second method is the animation file generated by AE on the network. (Web link)

Use 3.

Used in layout files

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

Use the network to load the ANIMATION file JSON generated by AE

private void loadUrl(String url) {
    client.newCall(request).enqueue(new Callback() {
        @Override 
        public void onFailure(Call call, IOException e) {}@Override
        public void onResponse(Call call, Response response) throws IOException {
            if (response.isSuccessful()) {
                try {
                    JSONObject json = new JSONObject(response.body().string());
                    LottieComposition.Factory
                            .fromJson(getResources(), json, new OnCompositionLoadedListener() {
                                @Override
                                public void onCompositionLoaded(LottieComposition composition) { setComposition(composition); }}); }catch (JSONException e) {
                }
            }
        }
    });
}

private  void setComposition(LottieComposition composition){
    animation_view.setProgress(0);
    animation_view.loop(true);
    animation_view.setComposition(composition);
    animation_view.playAnimation();
}
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.

Lottie main class diagram:

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:

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

{"v": "4.6.0", // BodyMovin version "fr": 29.9700012207031, // frame rate "IP ": 0, // start keyframe "op": 141.000005743048, // end keyframe "w": 800, / / animation width "h" : 800, height / / animation "DDD" : 0, "assets" : [...]. // Layers: [...] // Layer info}Copy the code

Parsing image resources

"Assets" : / / / resource information {/ / the first picture "id" : "image_0", "w" / / photo id: 58, / / picture width "h" : 31, / / picture height "u" : "images /, / / image path" p ": "Img_0.png" // image name}, {...} // NTH image]Copy the code

Parsing the layer

"The layers" : [/ / layer information {/ / the first layer of animation "DDD" : 0, "ind" : 0, / / layer id layer id "ty" : 4, / / layer type "nm" : "center_circle", "ks" : {...}, / / animation "ao" : 0, "shapes" : [...], "IP" : 0, / / inFrame the layers starting key frames "op" : 90, / / outFrame the layer over key frames "st" : 0, / / startFrame begin "bm" : 0, "sr" : 1}, {...} / / n layer animation]Copy the code

How to animate the sequence diagram

Using property animation to control progress, each progress change is notified to each layer, triggering LottieAnimationView redraw. The code is as follows:

public LottieDrawable(a) {
    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

Progress is passed to layers through the 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

Notification of 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

The final callback is 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

Lottie Edrawable is finally triggered to 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

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

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

Six, summarized

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

(4) Lottie is simple to use and easy to get started, so it is worth trying.

Seven, tips

  1. Students who do not want to use LottieAnimationView can use Lottie EdRawable to host Lottie animations as follows

    LottieDrawable tj = new LottieDrawable();
    LottieComposition.Factory.fromInputStream(stream, new OnCompositionLoadedListener() {
        @Override
        public void onCompositionLoaded(@Nullable LottieComposition composition) { drawable.setComposition(composition); }}); tj.loop(true);

Copy the code
  1. Some performance data of the animations generated by the design students can be viewed through Sample App, such as frame rate and other key factors (the author refused to render animations exceeding 7ms in the actual project).

Viii. Welfare at the end of the article

1. Lottie animation library

2. Official Lottie samples