前置知识:
Lottie 对动画的变换主要是通过 Matrix 实现, 因此需要了解 Matrix 相关知识,可以参考下面的博客:
https://blog.csdn.net/pathuang68/article/details/6991867
一、动画 Json 传入方法:
Json 动画传入的方式定义在 LottieComposition.Factory 中,分别为:
1. fromAssetFileName:从 assets 中加载,参数 filename 指 assets 中 json 的名称
2. fromRawFile:从 res/raw 中加载,参数 resId 就是 raw 中 json 的 id
3. fromInputStream:从 InputStream 中加载
4. fromJsonString:从 Json 字串中加载
5. fromJsonReader:从 JsonReader 中加载(如果需要解析的是 JsonObject,可以通过 new JsonReader(newStringReader(jsonObject))的方式加载,不过这种方式不推荐)
二、解析(Lottie 中的解析方法都位于 com.airbnb.lottie.parser 下):
1. 动画 json 传入后,最终会调用到 LottieComposition.Factory.fromJsonReader 方法,该方法会将解析事件委托给 AsyncCompositionLoader 异步线程,而 AsyncCompositionLoader 会调用 LottieComposition.Factory.fromJsonSync 方法,该方法调用 LottieCompositionParser.parse 方法开始进行动画 json 的解析,并将解析结果生成 LottieComposition。
2. AsyncCompositionLoader 中会调用 LottieCompositionParser.parse 方法进行具体解析,在 LottieCompositionParser.parse 方法中:
1) layers 会调用 parseLayers,parseLayers 调用 LayerParser.parse 解析
2) assets 会调用 parseAssets 解析
3) fonts 会调用 parseFonts,parseFonts 调用 FontParser.parse 解析
4) chars 会调用 parseChars,parseChars 调用 FontCharacterParser.parse 解析
5) w 会解析成 width
6) h 会解析成 height
7) ip 会解析成 startFrame
8) op 会解析成 endFrame
9) fr 会解析成 frameRate(动画速率)
10) v 会解析成 version(插件版本),进行版本支持性校验
3. LottieCompositionParser 会根据上面的解析结果生成 LottieComposition:
1) Rect bounds:通过 scaledWidth(width 与屏幕密度的乘积)、scaledHeight(height 与屏幕密度的乘积)确定
2) startFrame、endFrame、frameRate 就是上一步解析的值
3) layers、layerMap 是 layers 中解析的值
4) precomps 是 assets 中解析的值
5) images 是 assets 中解析出的图片的值
6) characters 是 chars 中解析的值
7) fonts 是 fonts 中解析的值
三、Layer 具体解析:
LayerParser 解析 layers 中的内容,其中关键是 ks,ks 的内容包含了动画用到的一些值,ks 的解析是通过 AnimatableTransformParser.parse 方法进行,LayerParser.parse 会通过上面解析的数据最终生成 Layer:
1) nm:解析为 layerName
2) ind:解析为 layerId
3) refId:解析为 refId
4) ty:解析为 layerType(附录 1)
5) parent:解析为 parentId
6) sw:解析为 solidWidth
7) sh:解析为 solidHeight
8) sc:解析为 solidColor
9) ks:解析为 transform
10) tt:解析为 mattType
11) masksProperties:数组,里面数据会通过 MaskParser.parse 解析成 Mask 并存入 masks 中
12) shapes:数组,里面数据会通过 ContentModelParser.parse 解析成 ContentModel 并存入 shapes 中
13) t:文本,会进一步解析:
(1) d:通过 AnimatableValueParser.parseDocumentData 解析成 text
(2) a:通过 AnimatableTextPropertiesParser.parse 方法解析成 textProperties
14) ef:Lottie 中目前不支持这种方式的效果,如果要用,需要将这种效果之直接添加到 shape 的 contents 中
15) sr:解析成 timeStretch
16) st:解析成 startFrame
17) w:解析成 preCompWidth
18) h:解析成 preCompHeight
19) ip:解析成 inFrame
20) op:解析成 outFrame
21) tm:解析成 timeRemapping
22) cl:解析成 cl
AnimatableTransformParser 解析 ks 内容,包括”a”(位置信息)、”p”(位移)、”s”(缩放)、”rz”(控制 3d 图层,暂时不支持)、”r”、”o”、”so”、”eo”,其实质是解析上面各字段下配置的 k 的值(解析方法为 KeyframesParser.parse),并根据 k 的值生成对应的 AnimatableValue,而 k 值用到的几个主要解析方式是:
1) PathParser:用于解析 k 数组,解析成 PointF,用于生成 AnimatablePathValue。
2) FloatParser:用于解析 k 数字,解析成 Float,用于生成 AnimatableFloatValue。
3) IntegerParser:用于解析 k 数字,解析成 Integer,用于生成 AnimatableIntegerValue。
4) ScaleXYParser:用于解析 k 数组,解析成 ScaleXY,用于生成 AnimatableScaleValue。
AnimatableTransformParser 中具体字段解析:
1) a(位置信息):调用 AnimatablePathValueParser.parse 解析 k 中配置的值,并将生成的结果赋值给 anchorPoint
2) p(位移信息):调用 AnimatablePathValueParser.parseSplitPath 解析,并将解析生成的结果赋值给 postion
3) s(缩放信息):调用 AnimatableValueParser.parseScale 解析,并将解析结果赋值给 scale
4) rz:3D 图层,不支持
5) r(翻转信息):调用 AnimatableValueParser.parseFloat 解析,并将解析结果赋值给 rotation
6) o(不透明度):调用 AnimatableValueParser.parseFloat 方法解析,并将解析结果赋值给 opacity
7) so(开始时不透明度):调用 AnimatableValueParser.parseFloat 方法解析,并将解析结果赋值给 startOpacity
8) eo(结束时不透明度):调用 AnimatableValueParser.parseFloat 方法解析,并将解析结果赋值给 endOpacity
四、AnimatablePathValueParser、AnimatableValueParser 重要方法解析:
1. AnimatablePathValueParser 中:
1) parse:若待解析的 JsonReader 中的值是数组,将调用 PathKeyframeParser.parse 方法解析并将解析结果存入 keyframes(List<Keyframe>)中,之后会调用 KeyframesParser.setEndFrames 将 keyframes 中 Keyframe 的 startFrame 与 endFrame 依次串联起来;若不是数组,就直接调用 JsonUtils.jsonToPoint 方法,并将解析结果生成的 Keyframe 存入 keyframes 中。最后根据 keyframes 生成 AnimatablePathValue。
2) parseSplitPath:
(1) k:调用 AnimatablePathValueParser.parse 解析,并将解析结果赋值给 pathAnimation
(2) x:若 JsonReader 值为 String,不解析,并将 hasExpressions 置为 true;若不是 String,则调用 AnimatableValueParser.parseFloat 解析,并将结果返回给 xAnimation
(3) y:若 JsonReader 值为 String,不解析,并将 hasExpressions 置为 true;若不是 String,则调用 AnimatableValueParser.parseFloat 解析,并将结果返回给 yAnimation
如果 pathAnimation 不为空(k 直接成功),则直接返回 pathAnimation;否则返回通过 xAnimation、yAnimation 生成的 AnimatableSplitDimensPathValue。
2. AnimatableValueParser 中 parseFloat、parseInteger、parsePoint 等方法中最终会调用 parse 方法解析,而 parse 方法则调用 KeyframesParser.parse 解析,:
1) parseFloat:调用 parse 并将 FloatParser 作为最终解析方法,解析结果生成 AnimatableFloatValue
2) parseInteger:调用 parse 并将 IntegerParser 作为最终解析方法,解析结果生成 AnimatableIntegerValue
3) parsePoint:调用 parse 并将 PointFParser 作为最终解析方法,解析结果生成 AnimatablePointValue
4) parseScale:调用 parse 并将 ScaleXYParser 作为最终解析方法,解析结果生成 AnimatableScaleValue
5) parseShapeData:调用 parse 并将 ShapeDataParser 作为最终解析方法,解析结果生成 AnimatableShapeValue
6) parseDocumentData:调用 parse 并将 DocumentDataParser 作为最终解析方法,解析结果生成 AnimatableTextFrame
7) parseColor:调用 parse 并将 ColorParser 作为最终解析方法,解析结果生成 AnimatableColorValue
8) parseGradientColor(渐变色):调用 parse 并将 GradientColorParser 作为最终解析方法,解析结果生成 AnimatableGradientColorValue
3. KeyframesParser.parse:
Parse 方法中首先会判断 JsonReader 值是否为 STRING 类型,如果是就直接返回空数据集 keyframes(List<Keyframe>),若不是,则解析 JsonReader 中 k 中配置的值,k 中的值基本是 3 种类型,分别是数字数组、对象数组、对象:
1) 若 k 中值为数组,则判断数组中元素是否为数字,若是,则调用 KeyframeParser.parse 解析整个数组(animated 为 false);若不是数字,则调用 KeyframeParser.parse 依次解析数组中元素(animated 为 true)
2) 若 k 中值不是数组,则调用 KeyframeParser.parse 解析整个数组(animated 为 false)
上面的解析结果都会存入 keyframes 中,最后会调用 setEndFrames 方法将 keyframes 中的 Keyframe 的 startFrame 与 endFrame 串联,最后将 keyframes 返回给调用者
4. KeyframeParser:
1) parse:判断传入的 animated 值,若为 true,则调用 parseKeyframe;否则调用 parseStaticValue
2) parseKeyframe 方法是用于解析 k 中对象数组中的值:
(1) t:解析成 startFrame
(2) s:调用传入的最终解析方法解析成 stratValue
(3) e:调用传入的最终解析方法解析成 endValue
(4) o:调用 JsonUtils.jsonToPoint 解析成 cp1
(5) i:调用 JsonUtils.JsonToPoint 解析成 cp2
(6) h:解析成 hold(若 h 值为 1 则为 true,否则为 false)
(7) to:调用 JsonUtils.jsonToPoint 解析成 pathCp1
(8) ti:调用 JsonUtils.jsonToPoint 解析成 pathCp2
解析完后会对解析的值进行进一步操作:
(1) 若 hold 为 ture,将 endValue 设置为 startValue,并将 interpolator 设置为 LINEAR_INTERPOLATOR;
(2) 若 hold 为 false,并且 cp1 与 cp2 均不为空,则通过 MiscUtils.clamp 筛选出合适的 cp1、cp2 的值,并通过 PathInterpolatorCompat.create 创建 interpolator(其中有 PathInterpolator 缓存的逻辑,想了解的可以看下)。
(3) 若为其他情况,则将 interpolator 设置为 LINEAR_INTERPOLATOR
最后,通过解析的 startValue、endValue、startFrame 以及创建的 interpolator 生成 Keyframe 并返回给调用者
3) parseStaticValue:调用传入的最终解析方法解析出 value,并根据 value 生成 Keyframe
5. FloatParser.parse:
调用 JsonUtils.valueFromObject 解析出 float 值并将结果与传入的 scale 相乘后返回
6. IntegerParser.parse:
调用调用 JsonUtils.valueFromObject 解析出 float 值并将结果与传入的 scale 相乘,再通过 Math.round 取出对应整值并返回
7. PointFParser.parse:
如果 reader 中值是 NUMBER 类型,直接通过 JsonReader.nextDouble 与 scale 生成 PointF;若 reader 为数组或对象,则调用 JsonUtils.jsonToPoint 方法解析出 PointF
8. ScaleXYParser.parse:
若是数组,就调用 JsonReader.beginArray 开始解析,否则就直接解析。解析 JsonReader 中连续的两个 double 值,并根据这两个值与 scale 生成 ScaleXY
9. ShapeDataParser.parse:
(1) c:解析成 closed
(2) v:调用 JsonUitls.jsonToPoints 方法解析成 pointsArray
(3) i:调用 JsonUtils.jsonToPoints 方法解析成 inTangents
(4) o:调用 JsonUtils.jsonToPoints 方法解析成 outTangents
若解析的 pointsArray 为空,就构建空的 ShapeData
若 pointsArray 不为空,则先取出 pointsArray 中第一个值,将其设置为 initialPoint。然后从第二个值开始循环 pointsArray 中的值,在 for 循环中,根据 pointsArray 中当前的值与 inTangents 中当前值生成 shapeCp1,pointsArray 中前一个值与 outTangents 中前一个值生成 shapeCp2,然后通过 shapeCp1 与 shapeCp2 以及 pointsArray 当前值生成 CubicCurveData 并加入 curves 中。
然后判断 closed 的值,如果 closed 为 true(标志这个 Shape 是封闭图形),则将 pointsArray 第一值作为当前值,最后一个值作为前一个值,进行上一步 for 循环中的操作,并将生成的 CubicCurveData 也填入 curves 中。
最后根据 initialPoint、closed、curves 生成 ShapeData。
10. DocumentDataParser.parse:
(1) t:解析成 text
(2) f:解析成 fontName
(3) s:解析成 size
(4) j:解析成 justification
(5) tr:解析成 tracking
(6) lh:解析成 lineHeight
(7) ls:解析成 baselineShift
(8) fc:调用 JsonUtils.jsonToColor 解析成 fillColor
(9) sc:调用 JsonUtils.jsonToColor 解析成 strokeColor
(10) sw:解析成 strokeWidth
(11) of:解析成 strokeOverFill
最后通过上面解析的值生成 DocumentData
11. ColorParser.parse:
若是数组,调用 JsonReader.beginArray 开始解析,否则直接解析。取 JsonReader 中连续的 4 个 double 值,分别解析成 r、g、b、a,若这四个值都小于,则说明它们被配置成色值的比例,将它们分别乘以 255,最后调用 Color.argb 生成颜色值(int 类型)
12. GradientColorParser.parse:
若为数组,则调用 reader.beginArray 开始解析,否则直接解析。将 JsonReader 中全部的 double 值解析出并存入 array 中,然后将 array 中的数据每 4 个进行循环,这四个值中第一个存入 positions,第二、三、四分别为 r、g、b 值,通过 r、g、b 生成 color 值后存入 colors,之后通过 positions、colors 值生成 gradientColor 并通过 addOpacityStopsToGradientIfNeeded 设置透明度(透明度是存放在颜色值的后面,不被 4 整除的部分),最后将 gradientColor 返回给调用者
13. JsonUtils:
1) jsonToColor:取出传入的 JsonReader 中连续的 3 个 double 值,分别设置为 r、g、b,然后调用 Color.argb 方法生成颜色值
2) jsonToPoints:若是数组,循环数组中的值,调用 jsonToPoint 解析出 PointF 并存入 points,最后将 points 返回
3) jsonToPoint:
(1) 若传入的 JsonReader 为数字,调用 jsonNumbersToPoint 并返回
(2) 若传入的 JsonReader 为数组,调用 jsonArrayToPoint 并返回
(3) 若传入的 JsonReader 为对象,调用 jsonObjectToPoint 并返回
4) jsonNumbersToPoint:
取出 JsonReader 连续的两个 double 值,分别置成 x、y,通过 x、y、scale 生成 PointF
5) jsonArrayToPoint:
取出数组中连续的两个 double 值,分别置成 x、y,通过 x、y、scale 生成 PointF
6) jsonObjectToPoint:
取出对象中的 x 值置为 x,对象中的 y 值置为 y,通过 x、y、scale 生成 PointF
7) valueFromObject:
若传入的 JsonReader 为数字,返回第一个 double 值;若是数组,返回数组中第一个值。
五、Shape 解析(layers 中的 shapes):
LayerParser 会调用 ContentModelParser.parse 将 shapes 数组依次解析成 ContentModel 并存入 shapes 中。
ContentModleParser.parse 首先会解析 ty,之后根据 ty 解析成不同的 ContentModel(附录 2)。
1. gr:调用 ShapeGroupParser.parse 解析成 ShapeGroup,这个是 Shape 组,里面会包含各种子 Shape。
ShapeGroupParser 中会调用 ContentModelParser.parse 将 it 数组中的内容依次解析成 ContentModel,并存入 items 中。
2. st:调用 ShapeStrokeParser.parse 解析成 ShapeStroke,Shape 线条的信息。
ShapeStrokeParser.parse 中会解析如下字段:
1) nm:name
2) c:color,调用 AnimatableValueParser.parseColor 解析
3) w:width,调用 AnimatableValueParser.parseFloat 解析
4) o:opacity,调用 AnimatableValueParser.parseInteger 解析
5) lc:capType,ShapeStroke.LineCapType 类型(附录 3)
6) lj:joinType,ShapeStroke.LineJoinType 类型(附录 4)
7) d:数组,首先会解析 n、v(v 会解析成 val):
(1) n 为 o,将 val 赋值给 offset
(2) n 为 d 或 g,将 val 添加到 lineDashPattern 中
解析完,如果 lineDashPattern 的个数如果是 1,就将该数据再加入 lineDashPattern 一次
最后会根据上面解析出的值生成 ShapeStroke
3. gs:调用 GradientStrokeParser.parse 解析成 GradientStroke
1) nm:name
2) o:opacity
3) t:gradientType,渐变类型(GradientType.Linear 或 GradientTypeRadial)
4) s:startPoint
5) e:endPoint
6) w:width
7) lc:capType
8) lj:joinType
9) d:lineDashPattern 或 offset
10) g:会进一步解析 g 中的字段
(1) p:points
(2) k:color,调用 AnimatableValueParser.parseGradientColor 并传入 points 解析
最后根据解析的值生成 GradientStroke
4. fl:调用 ShapeFillParser.parse 解析成 ShapeFill
1) nm:name
2) c:color
3) o:opacity
4) fillEnabled:fillEnabled,boolean 类型
5) r:fillTypeInt,int 类型,之后会根据 fillTypeInt 的值设置 fillType
最后根据解析的值生成 ShapeFill
5. gf:调用 GradientFillParser.parse 解析成 GradientFill
1) nm:name
2) g:color,AnimatableGradientColorValue 类型
3) o:opacity
4) t:gradientType
5) s:startPoint
6) e:endPoint
7) r:fillType
6. tr:调用 AnimatableTransFormParser.parse 解析成 AnimatableTransform
7. sh:调用 ShapePathParser.parse 解析成 ShapePath,Shape 的绘制路径
1) nm:name
2) ind:ind
3) ks:shape,调用 AnimatableValueParser.parseShapeData 解析
8. el:调用 CircleShapeParser.parse 解析成 CirCleShape
1) nm:name
2) p:position
3) s:size
4) d:reversed,boolean 类型,通过 d 的值是否为 3 确定
9. rc:调用 RectangleShapeParser.parse 解析成 RectangleShape
1) nm:name
2) p:position
3) s:size
4) r:roundedness,调用 AnimatableValueParser.parseFloat 解析
10. tm:调用 ShapeTrimPathParser.parse 解析成 ShapeTrimPath
1) s:start,AnimatableValueParser.parseFloat 解析
2) e:end,AnimatableValueParser.parseFloat 解析
3) o:offset,AnimatableValueParser.parseFloat 解析
4) nm:name
5) m:type,ShapeTrimPath.Type 类型,附录 5
11. sr:调用 PolystarShapeParser.parse 解析成 PolystarShape
1) nm:name
2) sy:type,PolystarShape.Type,附录 6
3) pt:points
4) p:position
5) r:totation
6) or:outerRadius,AnimatableValueParser.parseFloat 解析
7) os:outerRoundedness,AnimatableValueParser.parseFloat 解析
8) ir:innerRadius,AnimatableValueParser.parseFloat 解析
9) is:innerRoundedness,AnimatableValueParser.parseFloat 解析
12. mm:调用 MergePathParser.parse 解析成 MergePath,只支持 KitKat 及之后的版本
1) nm:name
2) mode:mode,MergePaths.MergePathsMode 类型,附录 7
13. rp:调用 RepeaterParser.parse 解析成 Repeater
1) nm:name
2) c:copies,AnimatableValueParser.parseFloat 解析
3) o:offset,AnimatableValueParser.parseFloat 解析
4) tr:transform
六、Assets 解析(assets):
LottieCompositionParser 中调用 parseAssets 方法解析 assets 中的内容。assets 中内容分两类,一类是图层信息,一类是图片信息:
1. 图层信息:
图层信息解析出的内容存放在 precomps 中,主要解析 id 与 layers 的内容。
assets 中的 layers 与外层的 layers 一样是调用 LayerParser.parse 解析
2. 图片信息(解析出的值会生成 LottieImageAsset 并存入 images 中):
1) id:解析成 id
2) w:解析成 width
3) h:解析成 height
4) u:解析成 relativeFolder
5) p:解析成 imageFileName
七、LottieDrawable 构建:
动画 json 解析完成后,会生成 LottieComposition,onCompositionLoaded 方法中将 LottieComposition 设置给 LottieDrawable。
LottieDrawable 的 setComposition 方法会通过 buildCompositionLayer、animator.setComposition、setScale、updateBounds、等方法重新构建 LottieDrawable
buildCompositionLayer 会重新构建 LottieDrawable 中的 CompositionLayer。
animator.setComposition 会重置 animator(LottieValueAnimator)minFrame、maxFrame、frame 与 lastFrameTimeNs 的信息,minFrame 会取原 minFrame 与 composition 的 startFrame(json 中的 ip 值)中的最大值,maxFrame 会取原 maxFrame 与 composition 的 endFrame(json 中的 op 值)中的最小值,frame 会通过一系列比较获取。
八、CompositionLayer 构建:
CompositionLayer 中存储了动画的所有层级的信息。
它在 LottieDrawable 中构建
compositionLayer = new CompositionLayer(this,LayerParser.parse(composition), composition.getLayers(), composition);
LayerParser.parse(composition)构建了最外层的 Layer,高和宽是 json 最外层的 h、w 的值。
composition.getLayers()获取的是 json 最外层 layers 中的内容。
CompositionLayer 的构造方法会遍历传入的 composition.getLayers 中的 Layer,并将 Layer 通过 BaseLayer.forModel 方法,根据 layerType 生成不同的 BaseLayer,对应关系如下表:
layerType
BaseLayer 子类
备注
Shape(ty=4)
ShapeLayer
PreComp(ty =0)
CompositionLayer
也就是 Assets 中的内容
Solid(ty=1)
SolidLayer
Image(ty=2)
ImageLayer
Null(ty=3)
NullLayer
Text(ty=5)
TextLayer
Unknown/default
null
生成的 BaseLayer 会存入 layerMap。
之后会根据前一个 BaseLayer 的 matteType(配置文件中的 tt)值判断是否为 mattedLayer,若是 MattedLayer 就将当前的 BaseLayer 设置为前一个 BaseLayer 的 MatteLayer,否则就添加到 layers 最前的位置。下表标识该 layer 是否为 MattedLayer
matteType
是否为 MattedLayer
Add/Invert(tt=1 或 2)
是
其他情况
否
最后会遍历 layerMap,找到每一个 BaseLayer 的 parentLayer(根据 BaseLayer 的 parentId 查找,parentId 对应于 json 中的 parent),并设置到该 BaseLayer 中。
九、绘制:
Json 解析完成后,会调用 setComposition 方法,该方法中会重新设置 LottieComposition,并调用 LottieDrawable.setComposition 方法刷新 LottieDrawable。
上面步骤完成后会调用 setImageDrawable、requestLayout 方法重绘 LottieAnimationView。
LottieAnimationView 的 onDraw 方法会调用 LottieDrawable 的 draw 方法(详细步骤需要查看 ImageView 的绘制流程)。下面具体分析下 LottieDrawable 的 draw 流程。
首先会确定动画的 scale,scale 是通过动画外层的 width 与 height 与 canvas 的比例确定,取高、宽比例中较小的值。若 scale 后的动画大于 canvas,会调用 canvas 的 translate、scale 方法重置 canvas。然后会将获取的 scale 填入矩阵 matrix。
之后会调用 BaseLayer.draw 方法绘制动画中的全部 Layer,具体步骤如下:
BaseLayer.draw()方法中有三个参数,分别是 canvas(画布)、parentMatrix(最外层动画 Matrix)、parentAlpha(最外层透明度)。
1. 调用 buildParentLayerListIfNeeded 方法构建出 CompositionLayer 的全部 parentLayer 并添加到 parentLayers 中。
2. 会将 parentMatrix 设置为 matrix,并将 parentLayers 中的 Layer 动画 Matrix 与传入的 matrix 相乘。
3. 然后,根据传入的 parentAlpha 与该 BaseLayer 的 transform 的 opacity 属性(即 json 中{“layers”:[{“ks” : {“o”: {…}}}]}中从 o 中解析出来的值,一般就是 o 中 k 的值)计算出透明度
4. 如果该 BaseLayer 没有 matteLayer 与 mask,就将 canvas、matrix、alpha 传入 drawLayer 方法进一步绘制,LottieDrawalbe 中调用的是 CompositionLayer 的 drawLayer 方法
十、CompositionLayer 绘制:
1. CompositionLayer 的 drawLayer 中首先保存 canvas 状态, 然后通过构建时生成的 Layer 的宽、高(具体分析见 CompositionLayer 构建)设置到 newClipRect(RectF 类型),然后将 newClipRect 按上步传入的 parentMatrix 进行变换。
2. 之后,会循环 CompositionLayer 中的 layers(见 CompositionLayer 的构建),并调用对应 BaseLayer 的 draw 方法将所有 layer 依次绘制出来,同时,会按照 newClipRect 重新裁剪 canva(这段代码可能会造成动画显示不全)。最后,将 canvas 设置回之前的状态
十一、 ShapeLayer 构建:
CompostionLayer 构造方法中遍历解析出的 layers(见三),通过 BaseLayer.forModel 根据生成对应的 BaseLayer。
ShapeLayer 对应的 type 为 4,BaseLayer.forModel 直接调用 ShapeLayer 构造函数生成 ShapeLayer。
ShapeLayer 构造函数首先通过 Layer 中的 shapes(List)构建 shapeGroup,然后通过 shapeGroup 构建出 contentGroup。(lottie 文件中也可能会配置 ShapeGroup 即”gr”。之后会调用 ContentGroup 的 setContents,setContents 会循环 ContentGroup 中的 contents,并调用 Content.setContents 方法将其前后的 contents 传入。
ContentGroup 构造方法中:
1. 通过 contentsFromModels 方法将 Layer 中的 shapes(即 List)通过 toContent 方法全部转换成对应的 Content(附录 2),并存入 contents 中
2. 通过 findTransform 方法取出该 ShapeLayer 对应的 AnimatableTransform(”tr”),然后通过 AnimatableTransform 生成 TransformKeyframeAnimation 赋值给 transformAnimation
3. 找出 contents 中全部的 GreedyContent 子类存入 greedyContents 中,并对 greedyContents 进行进一步操作。
十二、 ShapeLayer 绘制:
ShapeLayer 的 drawLayer 会委托给 contentGroup.draw 方法进行。contentGroup.draw 中首先会处理动画与透明度,之后遍历构造时生成的 contents,调用其中 DrawingContent 的子类的 draw 进行实际的绘制。
DrawingContent 子类见附录 2
DrawingConteng 实际上有 3 种:
1. 画线图(StrokeContent、GradientStrokeContent):
StrokeContent 与 GradientStrokeContent 的区别是线条的颜色是否为渐变色。
2. 画填充图(FillContent、GradientFillContent):
FillContent 与 GradientFillContent 的区别是填充色是否为渐变色。
3. 画需要重复的图(RepeaterContent):
十三、 StrokeContent 构建与绘制:
StrokeContent 是 BaseStrokeContent 的子类,大部分逻辑都在 BaseStrokeContent 中,以下是 BaseStrokeContent 的分析:
1. 构造函数:
构造函数中主要是完成的 Paint 以及 Animation 的初始化。
2. setContents:
setContents 会遍历与其同处一个 ContentGroup 下的其他 Content,找出其中的 TrimPathContent 与其对应的全部 PathContent,然后生成 PathGroup 并存入 pathGroups 中
3. draw:
1) 通过配置中的 width、color、alpha 对 paint 进行设置。
2) 遍历 pathGroups,对每一个 PathGroup 分情况处理:
(1) 若 pathGroup 中 trimPath 不为空,则调用 applyTrimPath 方法,applyTrimPath 方法中会通过 PathMeasure 根据 TrimPathContent 对 PathContent 构成的 Path 进行处理。
PathMeasure 用法可以参考:
https://blog.csdn.net/u013831257/article/details/51565591
(2) 若 pathGroup 中 trimPath 为空,直接通过 canvas.drawPath 绘制 PathContent 构成的 Path
十四、 动画过程:
Lottie 动画过程是通过 LottieValueAnimator 进行控制,animator 中会维护两个容器,一个存放向 Lottie 中注册的全部 ValueAnimator.AnimatorUpdateListener,一个存放向 Lottie 中注册的全部 AnimatorListener。
ValueAnimator.AnimatorUpdateListener 用于动画更新的监听,回调接口是 onAnimationUpdate。
AnimatorListener 用于动画开始、结束、取消、重复等监听。
LottieDrawable 构建的时候会向 animator 注册一个 AnimatorUpdateListener 的监听,这个监听会收到 animator 发送的动画更新的回调,在此回调中调用 compositionLayer 设置 progress 实现动画的更新。
十五、 附录:
1. LayerType 含义:
LayerType 对应于 json 文件 layers 中的 ty 字段,映射关系如下:
ty
LayerType
含义
0
PreComp
1
Solid
2
Image
图片
3
Null
4
Shape
绘制形状
5
Text
文字
6
Unknown
2. ContentModel(shape)中 type 含义,标黄的是 DrawingConent 的子类:
ty
ContentModel
toContent 类型
备注
gr
ShapeGroup
ContentGroup
Shape 组,里面包含子 Shape
st
ShapeStroke
StrokeContent
Shape 描边信息,如线的颜色、宽度、透明度等
gs
GradientStroke
GradientStrokeContent
fl
ShapeFill
FillContent
gf
GradientFill
GradientFillContent
tr
AnimatableTransform
null
Shape 的动画
sh
ShapePath
ShapeContent
Shape 的绘制路径
el
CircleShape
EllipseContent
rc
RectangleShape
RectangleContent
tm
ShapeTrimPath
TrimPathContent
修剪路径
sr
PolystarShape
PolystarContent
mm
MergePaths
MergePathsContent
rp
Repeater
RepeaterContent
3. ShapeStroke.LineCapType 类型:
index
ShapeStroke.LineCapType 类型
Paint.Cap(线帽子)
0
LineCapType.Butt
Paint.Cap.BUTT 无线帽
1
LineCapType.Round
Paint.Cap.ROUND 圆线帽
2
LineCapType.Unknown
Paint.Cap.SQUARE 方线帽
4. ShapeStroke.LineJoinType 类型:
index
ShapeStroke.LineJoinType 类型
Paint.Join(线段连接样式)
0
Miter
Paint.Join.MITER 锐角连接
1
Round
Paint.Join.ROUND 圆弧连接
2
Bevel
Paint.Join.BEVEL 斜接
5. ShapeTrimPath.Type 类型:
id
ShapeTrimPath.Type 类型
备注
1
Simultaneously
2
Individually
6. PolystarShape.Type 类型:
value
PolystarShape.Type 类型
备注
1
Star
2
Polygon
7. MergePaths.MergePathsMode 类型:
id
MergePaths.MergePathsMode
备注
1
Merge
2
Add
3
Subtract
4
Intersect
5
ExcludeIntersections
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于