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. 畫線圖(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 |
|
8.