当前位置:网站首页>Audio and video development journey (63) - animation and rendering of Lottie source code analysis
Audio and video development journey (63) - animation and rendering of Lottie source code analysis
2022-06-23 04:34:00 【Audio and video development journey】
Catalog
- Animation and drawing process
- LayerView Trees
- ShapeLayer Analysis of
- Lottie Pros and cons and rLottie、PAG Introduction to
- Information
- Harvest
In the last article, we learned to analyze Lottie Of json The analysis part . This is the animation and rendering part of our analysis .
The focus of the analysis : How to organize multiple layers layer The relationship between , Control the drawing and animation of different layers .
One 、 Animation and drawing process
We go through the entrance API function (LottieDrawable#setComposition、LottieDrawable#playAnimation) To analyze .
1.1 LottieDrawable#setComposition technological process
public boolean setComposition(LottieComposition composition) {
//......
clearComposition();
this.composition = composition;
// Build layers layer compositionlayer It works a little bit first andoid View In the tree ViewGroup, It can contain other View and ViewGroup
// complete CompositionLayer and ContentGroup The initialization There are mainly two inside TransformKeyframeAnimation
buildCompositionLayer();
// Trigger notifyUpdate, Then trigger Layer Of progress Recalculation and draw The callback ( Of course, the progress is 0, It will not trigger after various judgments composition Of drawlayer)
animator.setComposition(composition);
// Set the progress of the current animation
setProgress(animator.getAnimatedFraction());
......
}You can see setComposition The main call buildCompositionLayer and animator.setComposition To carry out CompositionLayer And others Layer(json Corresponding layers Field ) as well as ContentGroup、TransformKeyframeAnimation Equal initialization . Lottie Most used in animation Layer yes CompositionLayer、ShapeLayer as well as ImageLayer.
reflection : So what is ContentGroup、TransformKeyframeAnimation、 They and layer What is the relationship between ?( I will try to analyze and solve it later )
1.2 LottieDrawable#playAnimation technological process
1. LottieDrawable.playAnimation
2. LottieValueAnimator.playAnimation
3. LottieValueAnimator.setFrame
4. BaseLottieAnimator.notifyUpdate
5. Then trigger the callback (LottieDrawable.progressUpdateListener)AnimatorUpdateListener.onAnimationUpdate
6. CompositionLayer.setProgress --》 Calculate the current progress, Then set the progress of each layer in reverse order BaseLayer.setProgress
6.1(transform.setProgress(progress))TransformKeyframeAnimation.setProgress Set the progress of matrix transformation ( The zoom 、 transparency 、 Displacement, etc. )--》 Need to focus on analysis
6.2 animations.get(i).setProgress(progress); Traverse the settings for each animation Progress
7. BaseKeyframeAnimation.notifyListeners Callback to listener
8. BaseLayer.onValueChanged (invalidateSelf()) Trigger page redrawing ,--》 namely LottieDrawable.draw(android.graphics.Canvas, android.graphics.Matrix)
9. compositionLayer.draw(canvas, matrix, alpha) namely BaseLayer.draw --》 This is also a key method
10. drawLayer(canvas, matrix, alpha); namely BaseLayer.drawLayer This method is an abstract method , various layer Concrete realization
10.1 We use ImageLayer For example ( The key analysis ) ImageLayer.drawLayer First, through BaseKeyframeAnimation.getValue() This uses the previous animation changes progress Value , Get the current... According to the differentiator Bitmap
10.2 And then use canvas To draw , Complete the transformation of the picture LottieValueAnimator yes ValueAnimator Subclasses of , And implemented Choreographer.FrameCallback Interface . Through the progress transformation callback of attribute animation and VSYNC The signal doframe Callback to notify Layer Calculate the progress and value , And inform LottieDrawble To redraw , So as to achieve json in layers That is, all kinds of Layer Animation and drawing of layers .
But the concrete drawing still has Canvas To achieve , Can pass ImageLayer Of drawLayer
public void drawLayer(@NonNull Canvas canvas, Matrix parentMatrix, int parentAlpha) {
Bitmap bitmap = getBitmap();
if (bitmap == null || bitmap.isRecycled()) {
return;
}
float density = Utils.dpScale();
paint.setAlpha(parentAlpha);
if (colorFilterAnimation != null) {
paint.setColorFilter(colorFilterAnimation.getValue());
}
// Save the current state of the canvas
canvas.save();
// Yes matrix Apply the transformation to canvas All objects on
canvas.concat(parentMatrix);
//src Used to set to draw bitmap Region , That is, whether to cut
src.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
//dst It's used to set up canvas The display area on the canvas . Here you can see that the width and height of the display will be scaled according to the pixel density
dst.set(0, 0, (int) (bitmap.getWidth() * density), (int) (bitmap.getHeight() * density));
// first Rect(src) Represents the... To be drawn bitmap Area , You can cut the picture , If it's empty null The whole picture is displayed . the second Rect(dst) It's pictures in Canvas The area displayed in the canvas , That is to say bitmap Draw somewhere on the screen
// Through dynamic change dst, Can achieve Move 、 Zoom and so on , And scaling according to the pixel density of the screen , By changing src Handle the drawn pictures , It can also achieve many interesting effects , such as Show part of , Or gradually expand
canvas.drawBitmap(bitmap, src, dst, paint);
// Restore previously saved canvas state , and sava One-to-one correspondence
canvas.restore();
}as for ShapeLayer and CompositionLayer It's a little complicated , Now we will analyze it separately .
reflection : If there are multiple layers , How to ensure the association between multiple layers ( It's like ViewTree equally , How to manage the relationship between them and the order of drawing ).
Two 、LayerView Trees
Lottie There are all kinds of Layer:
So what is the relationship between them ? How to manage and control hierarchies ?
CompositionLayer Construction
public CompositionLayer(LottieDrawable lottieDrawable, Layer layerModel, List<Layer> layerModels,
LottieComposition composition) {
// Mainly TransformKeyframeAnimation The initialization
super(lottieDrawable, layerModel);
LongSparseArray<BaseLayer> layerMap =
new LongSparseArray<>(composition.getLayers().size());
BaseLayer mattedLayer = null;
// according to layers size , Produce each in reverse order Layer
for (int i = layerModels.size() - 1; i >= 0; i--) {
Layer lm = layerModels.get(i);
// This is an engineering method , according to layerType The structure corresponds to Layer
BaseLayer layer = BaseLayer.forModel(this, lm, lottieDrawable, composition);
if (layer == null) {
continue;
}
layerMap.put(layer.getLayerModel().getId(), layer);
......
}
for (int i = 0; i < layerMap.size(); i++) {
long key = layerMap.keyAt(i);
BaseLayer layerView = layerMap.get(key);
if (layerView == null) {
continue;
}
// determine layer Father son relationship between
BaseLayer parentLayer = layerMap.get(layerView.getLayerModel().getParentId());
if (parentLayer != null) {
layerView.setParentLayer(parentLayer);
}
}
}Factory method :BaseLayer#forModel
static BaseLayer forModel(
CompositionLayer compositionLayer, Layer layerModel, LottieDrawable drawable, LottieComposition composition) {
// Corresponding json in object->layers->ty
switch (layerModel.getLayerType()) {
// outline / Form layer This is the second one lottie The types used in animation are basically the most
case SHAPE:
return new ShapeLayer(drawable, layerModel, compositionLayer);
// Composite layer , amount to ViewTree Of ViewGroup Role
case PRE_COMP:
return new CompositionLayer(drawable, layerModel,
composition.getPrecomps(layerModel.getRefId()), composition);
// Fill the layer
case SOLID:
return new SolidLayer(drawable, layerModel);
// Picture layers This is also very common , Especially when making some template effects
case IMAGE:
return new ImageLayer(drawable, layerModel);
// Empty layer , Can be used for other layers parent
case NULL:
return new NullLayer(drawable, layerModel);
// Text layer
case TEXT:
return new TextLayer(drawable, layerModel);
case UNKNOWN:
default:
// Do nothing
Logger.warning("Unknown layer type " + layerModel.getLayerType());
return null;
}
}We see above layerView.setParentLayer(parentLayer); So this ParentLayer What's the use ? It is mainly used to determine the boundary of each layer and draw
// BaseLayer#buildParentLayerListIfNeeded
// This method determines the current layer boundary getBounds And call when drawing this layer draw
private void buildParentLayerListIfNeeded() {
if (parentLayers != null) {
return;
}
// If the layer has a parent layer , Innovation
if (parentLayer == null) {
parentLayers = Collections.emptyList();
return;
}
// Of this layer LayerViewTree
parentLayers = new ArrayList<>();
BaseLayer layer = parentLayer;
// Recursively find the parent layer of this layer 、 Grandfather layer 、 Great ancestor layer and so on
while (layer != null) {
parentLayers.add(layer);
layer = layer.parentLayer;
}
}BaseLayer#getBounds
public void getBounds(
RectF outBounds, Matrix parentMatrix, boolean applyParents) {
rect.set(0, 0, 0, 0);
// Determine the layer LayerViewTree:parentLayers
buildParentLayerListIfNeeded();
// Matrix transformation of sublayer , Based on the matrix transformation of the parent layer
boundsMatrix.set(parentMatrix);
if (applyParents) {
// Recursively call the parent layer amount matrix transformation , Do matrix multiplication
if (parentLayers != null) {
for (int i = parentLayers.size() - 1; i >= 0; i--) {
boundsMatrix.preConcat(parentLayers.get(i).transform.getMatrix());
}
} else if (parentLayer != null) {
boundsMatrix.preConcat(parentLayer.transform.getMatrix());
}
}
// Finally, multiply by the matrix transformation of the current layer , To determine the final boundary matrix
boundsMatrix.preConcat(transform.getMatrix());
}BaseLayer#draw and BaseLayer#getBounds The same matrix treatment .
adopt parentid Establish the layer LayerViewTree, Re measure and draw according to LayerView Determine your own bound and draw.
3、 ... and 、ShapeLayer Analysis of
The reason why ShapeLayer Take it out alone and say , It's because he's in lottie It is very important in animation , adopt ShapeLayer It's a vector graph, not bitmap To draw a subclass of layers . Specify attributes such as color and lineweight , use Path To define the figure to be drawn .
public class ShapeLayer extends BaseLayer {
......
// This ContentGroup What is it ? You can see ShapeLayer Of drawLayer and getBound It's all through contentGroup Acting .
private final ContentGroup contentGroup;
ShapeLayer(LottieDrawable lottieDrawable, Layer layerModel, CompositionLayer compositionLayer) {
......
//ContentGroup structure
contentGroup = new ContentGroup(lottieDrawable, this, shapeGroup);
contentGroup.setContents(Collections.<Content>emptyList(), Collections.<Content>emptyList());
}
@Override void drawLayer(@NonNull Canvas canvas, Matrix parentMatrix, int parentAlpha) {
// Called contentGroup Of draw
contentGroup.draw(canvas, parentMatrix, parentAlpha);
}
@Override public void getBounds(RectF outBounds, Matrix parentMatrix, boolean applyParents) {
......
contentGroup.getBounds(outBounds, boundsMatrix, applyParents);
}
......
}ContentGroup What is it ? You can see ShapeLayer Of drawLayer and getBound It's all through contentGroup Acting . Let's take a look at ContentGroup Of draw The implementation of the
public void draw(Canvas canvas, Matrix parentMatrix, int parentAlpha){
// Traversal call content, If it is DrawingContent Is to draw, What is... Over there DrawingContent Na
for (int i = contents.size() - 1; i >= 0; i--) {
Object content = contents.get(i);
if (content instanceof DrawingContent) {
((DrawingContent) content).draw(canvas, matrix, childAlpha);
}
}
}Traversal call content, If it is DrawingContent Is to draw, Which? content yes DrawingContent Na ?
We use FillContent For example , Let's see draw The implementation of the
public void draw(Canvas canvas, Matrix parentMatrix, int parentAlpha) {
......
// Get the color Transparency, etc. Set brush paint The color of the
int color = ((ColorKeyframeAnimation) this.colorAnimation).getIntValue();
int alpha = (int) ((parentAlpha / 255f * opacityAnimation.getValue() / 100f) * 255);
paint.setColor((clamp(alpha, 0, 255) << 24) | (color & 0xFFFFFF));
// Set up colorFilter
if (colorFilterAnimation != null) {
paint.setColorFilter(colorFilterAnimation.getValue());
}
......
// Set up path route
path.reset();
for (int i = 0; i < paths.size(); i++) {
path.addPath(paths.get(i).getPath(), parentMatrix);
}
// use cavas drawpath
canvas.drawPath(path, paint);
}Sure ShapeContent Of DrawingContent through Canvas To carry out draw Of .
Lottie That's all for the animation and rendering analysis of , About BaseKeyframeAnimation The main implementation Layer and DrawingContent Interpolation calculation of animation in , No detailed analysis , If you need to see it again .
reflection : Can we pass through OpenGL ES To render ?
5、 ... and 、Lottie Pros and cons and PAG Simple comparison of
Lottie The advantages and disadvantages of
advantage : Cross-platform support ( Although each end implements a set of ) Good performance It can be distributed through configuration “json And material ” updated . Shortcomings : Lottie Interaction and editing are not supported Lottie Compressed bitmaps are not supported , If you use png Equal bitmap , Need to be on your own tiny And other compression platforms for image compression 、 Reduce package volume . Lottie There is mask、matters when , It needs to be done first saveLayer, Call again drawLayer return . saveLayer It's a time-consuming operation , It needs to be allocated first 、 Draw a offscreen The buffer , This increases the rendering time
PAG The advantages and disadvantages of
PAG It is an animation component that Tencent just opened source yesterday , except lottie The advantages of , Support more AE Special effects , Support text and sequence frames , Support template editing , Use secondary value files instead of json, File size and parsing performance will be better Rendering level :Lottie The implementation of the rendering layer depends on the platform side interface , Different platforms may vary .PAG Render layers use C++ Realization , All platforms share the same set of implementations , The platform side simply encapsulates interface calls , Provide rendering environment , The rendering effect is consistent . PAG Deficiency , Rendering is based on google Open source skia 2d To achieve . Increased package size .4.0 The version of will be improved , Get rid of skia 2d. Realize simple rendering encapsulation by yourself ( I guess so opengl perhaps metal 、vulkan).
rlottie Brief introduction
[Samsung-rlottie](https://github.com/Samsung/rlottie) rLottie And lottie Workflow consistency , stay SDK The implementation is different ,rLottie No platform specific implementation is used , It's unity C++ Realization , Material support lottie Of json file , Vector rendering performance is good , But lack of platform encapsulation , Supported by AE Incomplete characteristics , Also does not support text 、 Sequence frame, etc This has not yet analyzed its source code implementation . Take time to analyze and learn .
6、 ... and 、 Information
- Lottie Implementation of ideas and source code analysis
- Lottie Analysis of animation principle
- reveal Lottie Advantages, disadvantages and principles of animation
- lottie-android Framework use and source code analysis
- Lottie Animation library Android End source code analysis
- Tencent open source PAG
- Samsung-rlottie
- Compare from the decoding and rendering level PAG And lottie
7、 ... and 、 Harvest
Through the study and analysis of this article
- Combed lottie Animation and rendering process
- LayerView The concept and understanding of tree , Make clear lottie How to manage differences layer The relationship between
- It focuses on CompositionLayer、BaseLayer、ImageLayer and ShapeLayer, among ShapeLayer Contain, ContentGroup
- A simple comparison lottie、PAG、rlottie
Thanks for reading Welcome to the official account “ The journey of audio and video development ”, Learn and grow together . Welcome to exchange
边栏推荐
- How to ensure application security
- Two ways to improve the writing efficiency of hard disk storage data
- Implementation of VGA protocol based on FPGA
- mysql如何删除表的一行数据
- 华为联机对战服务玩家快速匹配后,不同玩家收到的同一房间内玩家列表不同
- Form development mode
- 在线文本过滤小于指定长度工具
- 如何保证应用程序的安全性
- What is the open source database under Linux
- PTA:7-63 计算高考状元
猜你喜欢

How to ensure application security

怎么用好MySQL索引

Introduction to deep learning

Pytorch---Pytorch进行自定义Dataset

How does flutter achieve different zoom animation effects

Create a desktop shortcut to your appimage

Redis启动有问题

众昂矿业:新能源新材料产业链对萤石需求大增

【二叉樹進階】AVLTree - 平衡二叉搜索樹

How to use shell script to monitor file changes
随机推荐
Common events for elements
Compilation, installation and global configuration section description of haproxy
Can MySQL be used in Linux
Black horse PostgreSQL, why is it black in the end
理想汽车×OceanBase:当造车新势力遇上数据库新势力
P1347 排序(topo)
Background ribbon animation plug-in ribbon js
深度学习 简介
Pytorch---Pytorch进行自定义Dataset
AI 视频云 VS 窄带高清,谁是视频时代的宠儿
在word里,如何让页码从指定页开始编号
Bug STM32 advanced timer (haha, to tell you the truth, the hardware timer can't reflect its strength. In fact, I want to send the kernel timer. Just think about it. Take your time)
Pyspark, paid for data cleaning and uploading to the database
PTA: Simulation Implementation of 7-86 set (function template)
leetcode 91. Decode Ways 解码方法(中等)
自动化测试常见的面试题
在线JSON转CSharp(C#)Class工具
Particle animation background login page particles js
P1363 phantom maze (DFS)
How MySQL deletes a row of data in a table