Lottie源码浅探

Lottie(源码版本:2.5.4)动画步骤:

前置知识:

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<PointF>>)中,之后会调用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<T>>),若不是,则解析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<ContentModel>)构建shapeGroup,然后通过shapeGroup构建出contentGroup。(lottie文件中也可能会配置ShapeGroup即”gr”。之后会调用ContentGroup的setContents,setContents会循环ContentGroup中的contents,并调用Content.setContents方法将其前后的contents传入。

ContentGroup构造方法中:

1.      通过contentsFromModels方法将Layer中的shapes(即List<ContentModel>)通过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.      画线图(StrokeContentGradientStrokeContent):

StrokeContent与GradientStrokeContent的区别是线条的颜色是否为渐变色。

2.      画填充图(FillContentGradientFillContent):

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

 

 

8.       



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值