internal ShapeLayer(LottieDrawable lottieDrawable, Layer layerModel) : base(lottieDrawable, layerModel) { var shapeGroup = new ShapeGroup(layerModel.Name, layerModel.Shapes); _contentGroup = new ContentGroup(lottieDrawable, this, shapeGroup); _contentGroup.SetContents(new List <IContent>(), new List <IContent>()); }
internal static FontCharacter NewInstance(JsonObject json, LottieComposition composition) { var character = json.GetNamedString("ch").ElementAt(0); var size = (int)json.GetNamedNumber("size", 0); var width = json.GetNamedNumber("w", 0); var style = json.GetNamedString("style", ""); var fontFamily = json.GetNamedString("fFamily", ""); var shapesJson = json.GetNamedObject("data", null)?.GetNamedArray("shapes", null); IList <ShapeGroup> shapes = new List <ShapeGroup>(); if (shapesJson != null) { shapes = new List <ShapeGroup>(shapesJson.Count); for (uint i = 0; i < shapesJson.Count; i++) { shapes.Add((ShapeGroup)ShapeGroup.ShapeItemWithJson(shapesJson.GetObjectAt(i), composition)); } } return(new FontCharacter(shapes, character, size, width, style, fontFamily)); }
internal static Layer NewInstance(JsonObject json, LottieComposition composition) { var layerName = json.GetNamedString("nm"); var refId = json.GetNamedString("refId", string.Empty); if (layerName.EndsWith(".ai") || json.GetNamedString("cl", "").Equals("ai")) { composition.AddWarning("Convert your Illustrator layers to shape layers."); } var layerId = (long)json.GetNamedNumber("ind"); var solidWidth = 0; var solidHeight = 0; Color solidColor; var preCompWidth = 0; var preCompHeight = 0; LayerType layerType; var layerTypeInt = (int)json.GetNamedNumber("ty", -1); if (layerTypeInt < (int)LayerType.Unknown) { layerType = (LayerType)layerTypeInt; } else { layerType = LayerType.Unknown; } var parentId = (long)json.GetNamedNumber("parent", -1); if (layerType == LayerType.Solid) { solidWidth = (int)(json.GetNamedNumber("sw") * composition.DpScale); solidHeight = (int)(json.GetNamedNumber("sh") * composition.DpScale); solidColor = Utils.GetSolidColorBrush(json.GetNamedString("sc")); Debug.WriteLine("\tSolid=" + string.Format("{0:X}", solidColor) + " " + solidWidth + "x" + solidHeight + " " + composition.Bounds, Tag); } var transform = AnimatableTransform.Factory.NewInstance(json.GetNamedObject("ks"), composition); var matteType = (MatteType)(int)json.GetNamedNumber("tt", 0); IList <object> shapes = new List <object>(); IList <Mask> masks = new List <Mask>(); IList <IKeyframe <float?> > inOutKeyframes = new List <IKeyframe <float?> >(); var jsonMasks = json.GetNamedArray("masksProperties", null); if (jsonMasks != null) { for (var i = 0; i < jsonMasks.Count; i++) { var mask = Mask.Factory.NewMask(jsonMasks[i].GetObject(), composition); masks.Add(mask); } } var shapesJson = json.GetNamedArray("shapes", null); if (shapesJson != null) { for (var i = 0; i < shapesJson.Count; i++) { var shape = ShapeGroup.ShapeItemWithJson(shapesJson[i].GetObject(), composition); if (shape != null) { shapes.Add(shape); } } } if (json.ContainsKey("ef")) { composition.AddWarning("Lottie doesn't support layer effects. If you are using them for " + " fills, strokes, trim paths etc. then try adding them directly as contents " + " in your shape."); } var timeStretch = (float)json.GetNamedNumber("sr", 1.0); var startFrame = (float)json.GetNamedNumber("st"); var frames = composition.DurationFrames; var startProgress = startFrame / frames; if (layerType == LayerType.PreComp) { preCompWidth = (int)(json.GetNamedNumber("w") * composition.DpScale); preCompHeight = (int)(json.GetNamedNumber("h") * composition.DpScale); } var inFrame = (float)json.GetNamedNumber("ip"); var outFrame = (float)json.GetNamedNumber("op"); // Before the in frame if (inFrame > 0) { var preKeyframe = new Keyframe <float?>(composition, 0f, 0f, null, 0f, inFrame); inOutKeyframes.Add(preKeyframe); } // The + 1 is because the animation should be visible on the out frame itself. outFrame = outFrame > 0 ? outFrame : composition.EndFrame + 1; var visibleKeyframe = new Keyframe <float?>(composition, 1f, 1f, null, inFrame, outFrame); inOutKeyframes.Add(visibleKeyframe); if (outFrame <= composition.DurationFrames) { var outKeyframe = new Keyframe <float?>(composition, 0f, 0f, null, outFrame, composition.EndFrame); inOutKeyframes.Add(outKeyframe); } return(new Layer(shapes, composition, layerName, layerId, layerType, parentId, refId, masks, transform, solidWidth, solidHeight, solidColor, timeStretch, startProgress, preCompWidth, preCompHeight, inOutKeyframes, matteType)); }
internal ContentGroup(LottieDrawable lottieDrawable, BaseLayer layer, ShapeGroup shapeGroup) : this(lottieDrawable, layer, shapeGroup.Name, ContentsFromModels(lottieDrawable, layer, shapeGroup.Items), FindTransform(shapeGroup.Items)) { }
internal static Layer NewInstance(JsonObject json, LottieComposition composition) { var layerName = json.GetNamedString("nm"); var refId = json.GetNamedString("refId", string.Empty); if (layerName.EndsWith(".ai") || json.GetNamedString("cl", "").Equals("ai")) { composition.AddWarning("Convert your Illustrator layers to shape layers."); } var layerId = (long)json.GetNamedNumber("ind"); var solidWidth = 0; var solidHeight = 0; Color solidColor; var preCompWidth = 0; var preCompHeight = 0; LayerType layerType; var layerTypeInt = (int)json.GetNamedNumber("ty", -1); if (layerTypeInt < (int)LayerType.Unknown) { layerType = (LayerType)layerTypeInt; } else { layerType = LayerType.Unknown; } if (layerType == LayerType.Text && !Utils.IsAtLeastVersion(composition, 4, 8, 0)) { layerType = LayerType.Unknown; composition.AddWarning("Text is only supported on bodymovin >= 4.8.0"); } var parentId = (long)json.GetNamedNumber("parent", -1); if (layerType == LayerType.Solid) { solidWidth = (int)(json.GetNamedNumber("sw") * composition.DpScale); solidHeight = (int)(json.GetNamedNumber("sh") * composition.DpScale); solidColor = Utils.GetSolidColorBrush(json.GetNamedString("sc")); Debug.WriteLine("\tSolid=" + string.Format("{0:X}", solidColor) + " " + solidWidth + "x" + solidHeight + " " + composition.Bounds, Tag); } var transform = AnimatableTransform.Factory.NewInstance(json.GetNamedObject("ks"), composition); var matteType = (MatteType)(int)json.GetNamedNumber("tt", 0); var masks = new List <Mask>(); var inOutKeyframes = new List <IKeyframe <float?> >(); var jsonMasks = json.GetNamedArray("masksProperties", null); if (jsonMasks != null) { for (var i = 0; i < jsonMasks.Count; i++) { var mask = Mask.Factory.NewMask(jsonMasks[i].GetObject(), composition); masks.Add(mask); } } var shapes = new List <IContentModel>(); var shapesJson = json.GetNamedArray("shapes", null); if (shapesJson != null) { for (var i = 0; i < shapesJson.Count; i++) { var shape = ShapeGroup.ShapeItemWithJson(shapesJson[i].GetObject(), composition); if (shape != null) { shapes.Add(shape); } } } AnimatableTextFrame text = null; AnimatableTextProperties textProperties = null; var textJson = json.GetNamedObject("t", null); if (textJson != null) { text = AnimatableTextFrame.Factory.NewInstance(textJson.GetNamedObject("d", null), composition); var namedArray = textJson.GetNamedArray("a", null); var propertiesJson = namedArray?.Count > 0 ? namedArray.GetObjectAt(0) : null; textProperties = AnimatableTextProperties.Factory.NewInstance(propertiesJson, composition); } if (json.ContainsKey("ef")) { composition.AddWarning("Lottie doesn't support layer effects. If you are using them for " + " fills, strokes, trim paths etc. then try adding them directly as contents " + " in your shape."); } var timeStretch = (float)json.GetNamedNumber("sr", 1.0); var startFrame = (float)json.GetNamedNumber("st"); var frames = composition.DurationFrames; var startProgress = startFrame / frames; if (layerType == LayerType.PreComp) { preCompWidth = (int)(json.GetNamedNumber("w") * composition.DpScale); preCompHeight = (int)(json.GetNamedNumber("h") * composition.DpScale); } // Bodymovin pre-scales the in frame and out frame by the time stretch. However, that will // cause the stretch to be double counted since the in out animation gets treated the same // as all other animations and will have stretch applied to it again. var inFrame = (float)json.GetNamedNumber("ip") / timeStretch; var outFrame = (float)json.GetNamedNumber("op") / timeStretch; // Before the in frame if (inFrame > 0) { var preKeyframe = new Keyframe <float?>(composition, 0f, 0f, null, 0f, inFrame); inOutKeyframes.Add(preKeyframe); } // The + 1 is because the animation should be visible on the out frame itself. outFrame = outFrame > 0 ? outFrame : composition.EndFrame + 1; var visibleKeyframe = new Keyframe <float?>(composition, 1f, 1f, null, inFrame, outFrame); inOutKeyframes.Add(visibleKeyframe); var outKeyframe = new Keyframe <float?>(composition, 0f, 0f, null, outFrame, float.MaxValue); inOutKeyframes.Add(outKeyframe); AnimatableFloatValue timeRemapping = null; if (json.ContainsKey("tm")) { timeRemapping = AnimatableFloatValue.Factory.NewInstance(json.GetNamedObject("tm", null), composition, false); } return(new Layer(shapes, composition, layerName, layerId, layerType, parentId, refId, masks, transform, solidWidth, solidHeight, solidColor, timeStretch, startProgress, preCompWidth, preCompHeight, text, textProperties, inOutKeyframes, matteType, timeRemapping)); }
internal ContentGroup(LottieDrawable lottieDrawable, BaseLayer layer, ShapeGroup shapeGroup) { Name = shapeGroup.Name; var items = shapeGroup.Items; if (items.Count == 0) { return; } if (items[items.Count - 1] is AnimatableTransform animatableTransform) { _transformAnimation = animatableTransform.CreateAnimation(); _transformAnimation.AddAnimationsToLayer(layer); _transformAnimation.ValueChanged += (sender, args) => { lottieDrawable.InvalidateSelf(); }; } for (var i = 0; i < items.Count; i++) { var item = items[i]; if (item is ShapeFill) { _contents.Add(new FillContent(lottieDrawable, layer, (ShapeFill)item)); } else if (item is GradientFill) { _contents.Add(new GradientFillContent(lottieDrawable, layer, (GradientFill)item)); } else if (item is ShapeStroke) { _contents.Add(new StrokeContent(lottieDrawable, layer, (ShapeStroke)item)); } else if (item is GradientStroke) { _contents.Add(new GradientStrokeContent(lottieDrawable, layer, (GradientStroke)item)); } else if (item is ShapeGroup) { _contents.Add(new ContentGroup(lottieDrawable, layer, (ShapeGroup)item)); } else if (item is RectangleShape) { _contents.Add(new RectangleContent(lottieDrawable, layer, (RectangleShape)item)); } else if (item is CircleShape) { _contents.Add(new EllipseContent(lottieDrawable, layer, (CircleShape)item)); } else if (item is ShapePath) { _contents.Add(new ShapeContent(lottieDrawable, layer, (ShapePath)item)); } else if (item is PolystarShape) { _contents.Add(new PolystarContent(lottieDrawable, layer, (PolystarShape)item)); } else if (item is ShapeTrimPath) { _contents.Add(new TrimPathContent(layer, (ShapeTrimPath)item)); } else { if (item is MergePaths mergePaths) { if (lottieDrawable.EnableMergePathsForKitKatAndAbove()) { _contents.Add(new MergePathsContent(mergePaths)); } else { Debug.WriteLine("Animation contains merge paths but they are disabled.", Tag); } } } } IList <IContent> contentsToRemove = new List <IContent>(); MergePathsContent currentMergePathsContent = null; for (var i = _contents.Count - 1; i >= 0; i--) { var content = _contents[i]; if (content is MergePathsContent mergePathsContent) { currentMergePathsContent = mergePathsContent; } if (currentMergePathsContent != null && content != currentMergePathsContent) { currentMergePathsContent.AddContentIfNeeded(content); contentsToRemove.Add(content); } } for (var i = _contents.Count - 1; i >= 0; i--) { if (contentsToRemove.Contains(_contents[i])) { _contents.RemoveAt(i); } } }