diff --git a/LotteAnimator.xcodeproj/project.pbxproj b/LotteAnimator.xcodeproj/project.pbxproj index 9ec0539dd7..9d8307be2a 100644 --- a/LotteAnimator.xcodeproj/project.pbxproj +++ b/LotteAnimator.xcodeproj/project.pbxproj @@ -35,7 +35,6 @@ 620A565F1D1C81750030EBFB /* LAAnimatablePointValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 620A565E1D1C81750030EBFB /* LAAnimatablePointValue.m */; }; 620A56621D1C81850030EBFB /* LAAnimatableNumberValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 620A56611D1C81850030EBFB /* LAAnimatableNumberValue.m */; }; 620A56651D1C81930030EBFB /* LAAnimatableShapeValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 620A56641D1C81930030EBFB /* LAAnimatableShapeValue.m */; }; - 620CD7CD1D3415F000055AD1 /* LAAnimatableRectValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 620CD7CC1D3415F000055AD1 /* LAAnimatableRectValue.m */; }; 620CD7D01D343A2500055AD1 /* LAAnimatableScaleValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 620CD7CF1D343A2500055AD1 /* LAAnimatableScaleValue.m */; }; 620CD7E51D38180800055AD1 /* LAGroupLayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 620CD7E41D38180800055AD1 /* LAGroupLayerView.m */; }; 62FE408D1D3EC81C00CA389D /* CAAnimationGroup+LAAnimatableGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FE408C1D3EC81C00CA389D /* CAAnimationGroup+LAAnimatableGroup.m */; }; @@ -90,6 +89,11 @@ 62FE41C21D46886600CA389D /* goftldalt.json in Resources */ = {isa = PBXBuildFile; fileRef = 62FE41BE1D46886600CA389D /* goftldalt.json */; }; 62FE41C31D46886600CA389D /* govtid.json in Resources */ = {isa = PBXBuildFile; fileRef = 62FE41BF1D46886600CA389D /* govtid.json */; }; 62FE41C41D46886600CA389D /* selfie.json in Resources */ = {isa = PBXBuildFile; fileRef = 62FE41C01D46886600CA389D /* selfie.json */; }; + 62FE41C61D46D5C900CA389D /* masktest.json in Resources */ = {isa = PBXBuildFile; fileRef = 62FE41C51D46D5C900CA389D /* masktest.json */; }; + 62FE41C81D47D92E00CA389D /* masksAndSolids.json in Resources */ = {isa = PBXBuildFile; fileRef = 62FE41C71D47D92E00CA389D /* masksAndSolids.json */; }; + 62FE41CB1D48004A00CA389D /* LAEllipseShapeLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FE41CA1D48004A00CA389D /* LAEllipseShapeLayer.m */; }; + 62FE41CD1D4804E400CA389D /* circleTest.json in Resources */ = {isa = PBXBuildFile; fileRef = 62FE41CC1D4804E400CA389D /* circleTest.json */; }; + 62FE41D31D4829E100CA389D /* LAShapeTrimPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FE41D21D4829E100CA389D /* LAShapeTrimPath.m */; }; F5B4E946F7B28B4594824641 /* libPods-LotteAnimator.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BC68632413866F85CEACB7EA /* libPods-LotteAnimator.a */; }; /* End PBXBuildFile section */ @@ -150,8 +154,6 @@ 620A56611D1C81850030EBFB /* LAAnimatableNumberValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableNumberValue.m; sourceTree = ""; }; 620A56631D1C81930030EBFB /* LAAnimatableShapeValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAAnimatableShapeValue.h; sourceTree = ""; }; 620A56641D1C81930030EBFB /* LAAnimatableShapeValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableShapeValue.m; sourceTree = ""; }; - 620CD7CB1D3415F000055AD1 /* LAAnimatableRectValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAAnimatableRectValue.h; sourceTree = ""; }; - 620CD7CC1D3415F000055AD1 /* LAAnimatableRectValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableRectValue.m; sourceTree = ""; }; 620CD7CE1D343A2500055AD1 /* LAAnimatableScaleValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAAnimatableScaleValue.h; sourceTree = ""; }; 620CD7CF1D343A2500055AD1 /* LAAnimatableScaleValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableScaleValue.m; sourceTree = ""; }; 620CD7E31D38180800055AD1 /* LAGroupLayerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAGroupLayerView.h; sourceTree = ""; }; @@ -214,6 +216,13 @@ 62FE41BE1D46886600CA389D /* goftldalt.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = goftldalt.json; sourceTree = ""; }; 62FE41BF1D46886600CA389D /* govtid.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = govtid.json; sourceTree = ""; }; 62FE41C01D46886600CA389D /* selfie.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = selfie.json; sourceTree = ""; }; + 62FE41C51D46D5C900CA389D /* masktest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = masktest.json; sourceTree = ""; }; + 62FE41C71D47D92E00CA389D /* masksAndSolids.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = masksAndSolids.json; sourceTree = ""; }; + 62FE41C91D48004A00CA389D /* LAEllipseShapeLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAEllipseShapeLayer.h; sourceTree = ""; }; + 62FE41CA1D48004A00CA389D /* LAEllipseShapeLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAEllipseShapeLayer.m; sourceTree = ""; }; + 62FE41CC1D4804E400CA389D /* circleTest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = circleTest.json; sourceTree = ""; }; + 62FE41D11D4829E100CA389D /* LAShapeTrimPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAShapeTrimPath.h; sourceTree = ""; }; + 62FE41D21D4829E100CA389D /* LAShapeTrimPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAShapeTrimPath.m; sourceTree = ""; }; AEE1A33E4CE2F6024DE7793E /* Pods-LotteAnimator.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LotteAnimator.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LotteAnimator/Pods-LotteAnimator.debug.xcconfig"; sourceTree = ""; }; BC68632413866F85CEACB7EA /* libPods-LotteAnimator.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LotteAnimator.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -277,6 +286,8 @@ 486BE04D1D36F1BE00CD14A0 /* LAShapeLayerView.m */, 62FE40E61D3FFBB400CA389D /* LARectShapeLayer.h */, 62FE40E71D3FFBB400CA389D /* LARectShapeLayer.m */, + 62FE41C91D48004A00CA389D /* LAEllipseShapeLayer.h */, + 62FE41CA1D48004A00CA389D /* LAEllipseShapeLayer.m */, 4804B2FD1C1F55E600DA8AF7 /* ViewController.h */, 4804B2FE1C1F55E600DA8AF7 /* ViewController.m */, 48372A621C20A91C00AD0293 /* LAJSONExplorerViewController.h */, @@ -315,6 +326,8 @@ 48372A4E1C1F99C600AD0293 /* LAShapeGroup.m */, 48372A561C209A6C00AD0293 /* LAShapeStroke.h */, 48372A571C209A6C00AD0293 /* LAShapeStroke.m */, + 62FE41D11D4829E100CA389D /* LAShapeTrimPath.h */, + 62FE41D21D4829E100CA389D /* LAShapeTrimPath.m */, 48372A591C209A7A00AD0293 /* LAShapeFill.h */, 48372A5A1C209A7A00AD0293 /* LAShapeFill.m */, 48372A5C1C209A8900AD0293 /* LAShapeTransform.h */, @@ -345,6 +358,9 @@ 48372A651C20B04300AD0293 /* JSONExamples */ = { isa = PBXGroup; children = ( + 62FE41CC1D4804E400CA389D /* circleTest.json */, + 62FE41C71D47D92E00CA389D /* masksAndSolids.json */, + 62FE41C51D46D5C900CA389D /* masktest.json */, 62FE41BD1D46886600CA389D /* allset.json */, 62FE41BE1D46886600CA389D /* goftldalt.json */, 62FE41BF1D46886600CA389D /* govtid.json */, @@ -413,8 +429,6 @@ 62FE40E41D3FF78800CA389D /* LAAnimatableBoundsValue.m */, 620CD7CE1D343A2500055AD1 /* LAAnimatableScaleValue.h */, 620CD7CF1D343A2500055AD1 /* LAAnimatableScaleValue.m */, - 620CD7CB1D3415F000055AD1 /* LAAnimatableRectValue.h */, - 620CD7CC1D3415F000055AD1 /* LAAnimatableRectValue.m */, 62FE408B1D3EC81C00CA389D /* CAAnimationGroup+LAAnimatableGroup.h */, 62FE408C1D3EC81C00CA389D /* CAAnimationGroup+LAAnimatableGroup.m */, ); @@ -505,6 +519,7 @@ 4804B3041C1F55E600DA8AF7 /* Assets.xcassets in Resources */, 62FE40D11D3EDC7400CA389D /* 062_AnimateTransformParented.json in Resources */, 62FE40D71D3EDC7400CA389D /* 100_House_AnimateInAndOut.json in Resources */, + 62FE41CD1D4804E400CA389D /* circleTest.json in Resources */, 62FE40D41D3EDC7400CA389D /* 071_AnimatePathShape.json in Resources */, 62FE40CE1D3EDC7400CA389D /* 058_AnimateTransformPositionHoldKeyframe.json in Resources */, 62FE40CC1D3EDC7400CA389D /* 056_AnimateTransformPositionCustomEaseIn.json in Resources */, @@ -522,6 +537,7 @@ 62FE40CA1D3EDC7400CA389D /* 054_AnimateTransformPositionEaseOut.json in Resources */, 62FE40B51D3EDC7400CA389D /* 002_ShapeLayerLine_01.json in Resources */, 62FE40DD1D3FF0D900CA389D /* Heart58OnOff.json in Resources */, + 62FE41C81D47D92E00CA389D /* masksAndSolids.json in Resources */, 62FE40B81D3EDC7400CA389D /* 005_TwoShapeLayerSquaresDifferent_01.json in Resources */, 62FE40C01D3EDC7400CA389D /* 013_ShapeMasked_01.json in Resources */, 486BE04B1D36E06C00CD14A0 /* newMoovin.json in Resources */, @@ -539,6 +555,7 @@ 62FE40EA1D401C0700CA389D /* scaleTest.json in Resources */, 62FE40BE1D3EDC7400CA389D /* 011_MergePaths_01.json in Resources */, 62FE40BC1D3EDC7400CA389D /* 009_ShapeLayerRepeater_01.json in Resources */, + 62FE41C61D46D5C900CA389D /* masktest.json in Resources */, 62FE40C21D3EDC7400CA389D /* 015_DottedLine_01.json in Resources */, 62FE40CD1D3EDC7400CA389D /* 057_AnimateTransformPositionCustomEaseInout.json in Resources */, ); @@ -602,9 +619,11 @@ 4804B31E1C1F757600DA8AF7 /* UIColor+Expanded.m in Sources */, 4804B2FF1C1F55E600DA8AF7 /* ViewController.m in Sources */, 48372A641C20A91C00AD0293 /* LAJSONExplorerViewController.m in Sources */, + 62FE41D31D4829E100CA389D /* LAShapeTrimPath.m in Sources */, 62FE41431D41862200CA389D /* LAAnimatableLayer.m in Sources */, 620A56651D1C81930030EBFB /* LAAnimatableShapeValue.m in Sources */, 4804B3191C1F6DEA00DA8AF7 /* LAComposition.m in Sources */, + 62FE41CB1D48004A00CA389D /* LAEllipseShapeLayer.m in Sources */, 4804B2FC1C1F55E600DA8AF7 /* AppDelegate.m in Sources */, 4804B3211C1F761800DA8AF7 /* BWMath.m in Sources */, 62FE40E51D3FF78800CA389D /* LAAnimatableBoundsValue.m in Sources */, @@ -626,7 +645,6 @@ 48372A551C209A5F00AD0293 /* LAShapePath.m in Sources */, 620CD7E51D38180800055AD1 /* LAGroupLayerView.m in Sources */, 48372AB71C20D97200AD0293 /* LAShapeCircle.m in Sources */, - 620CD7CD1D3415F000055AD1 /* LAAnimatableRectValue.m in Sources */, 620A565C1D1C81610030EBFB /* LAAnimatableColorValue.m in Sources */, 48372A5E1C209A8900AD0293 /* LAShapeTransform.m in Sources */, 62FE41BC1D42DD8500CA389D /* LAMaskLayer.m in Sources */, diff --git a/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/UserInterfaceState.xcuserstate b/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/UserInterfaceState.xcuserstate index d2488463bc..85264755fd 100644 Binary files a/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/UserInterfaceState.xcuserstate and b/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 453d7341b4..c3cce40adc 100644 --- a/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/LotteAnimator.xcworkspace/xcuserdata/brandon_withrow.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -67,13 +67,13 @@ shouldBeEnabled = "Yes" ignoreCount = "0" continueAfterRunningActions = "No" - filePath = "LotteAnimator/LAShapeCircle.m" - timestampString = "490729764.635343" + filePath = "LotteAnimator/LAMaskLayer.m" + timestampString = "491264085.840767" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "14" - endingLineNumber = "14" - landmarkName = "-initWithJSON:frameRate:" + startingLineNumber = "54" + endingLineNumber = "54" + landmarkName = "-renderInContext:" landmarkType = "5"> @@ -83,13 +83,13 @@ shouldBeEnabled = "Yes" ignoreCount = "0" continueAfterRunningActions = "No" - filePath = "LotteAnimator/LAAnimatableScaleValue.m" - timestampString = "490740783.490737" + filePath = "LotteAnimator/LAMaskLayer.m" + timestampString = "491264087.213296" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "82" - endingLineNumber = "82" - landmarkName = "-_buildAnimationForKeyframes:" + startingLineNumber = "50" + endingLineNumber = "50" + landmarkName = "-drawInContext:" landmarkType = "5"> @@ -100,7 +100,7 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "LotteAnimator/LAAnimatableLayer.m" - timestampString = "490920717.958644" + timestampString = "491266116.833188" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" startingLineNumber = "56" @@ -109,53 +109,5 @@ landmarkType = "5"> - - - - - - - - - - - - diff --git a/LotteAnimator/LAAnimatableLayer.m b/LotteAnimator/LAAnimatableLayer.m index 08c12c777f..1c7f672f20 100644 --- a/LotteAnimator/LAAnimatableLayer.m +++ b/LotteAnimator/LAAnimatableLayer.m @@ -93,5 +93,4 @@ layer.beginTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; } - @end diff --git a/LotteAnimator/LAAnimatableRectValue.h b/LotteAnimator/LAAnimatableRectValue.h deleted file mode 100644 index ca8a283716..0000000000 --- a/LotteAnimator/LAAnimatableRectValue.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// LAAnimatableSizeValue.h -// LotteAnimator -// -// Created by brandon_withrow on 7/11/16. -// Copyright © 2016 Brandon Withrow. All rights reserved. -// - -#import - -@interface LAAnimatableRectValue : NSObject - -- (instancetype)initWithRectValues:(NSDictionary *)rectValues frameRate:(NSNumber *)frameRate; - -@property (nonatomic, readonly) CGRect initialRect; -@property (nonatomic, readonly) NSArray *rectKeyframes; -@property (nonatomic, readonly) NSArray *keyTimes; -@property (nonatomic, readonly) NSArray *timingFunctions; -@property (nonatomic, readonly) NSTimeInterval delay; -@property (nonatomic, readonly) NSTimeInterval duration; -@property (nonatomic, readonly) BOOL hasAnimation; -@property (nonatomic, readonly) NSNumber *startFrame; -@property (nonatomic, readonly) NSNumber *durationFrames; -@property (nonatomic, readonly) NSNumber *frameRate; - -- (CAKeyframeAnimation *)animationForKeyPath:(NSString *)keypath; - -@end diff --git a/LotteAnimator/LAAnimatableRectValue.m b/LotteAnimator/LAAnimatableRectValue.m deleted file mode 100644 index 40023029b4..0000000000 --- a/LotteAnimator/LAAnimatableRectValue.m +++ /dev/null @@ -1,22 +0,0 @@ -// -// LAAnimatableSizeValue.m -// LotteAnimator -// -// Created by brandon_withrow on 7/11/16. -// Copyright © 2016 Brandon Withrow. All rights reserved. -// - -#import "LAAnimatableRectValue.h" - -@implementation LAAnimatableRectValue - -- (instancetype)initWithRectValues:(NSDictionary *)rectValues frameRate:(NSNumber *)frameRate { - self = [super init]; - if (self) { - _frameRate = frameRate; - - } - return self; -} - -@end diff --git a/LotteAnimator/LACompView.m b/LotteAnimator/LACompView.m index 451393b53d..26fa22b046 100644 --- a/LotteAnimator/LACompView.m +++ b/LotteAnimator/LACompView.m @@ -28,11 +28,20 @@ NSMutableDictionary *layerMap = [NSMutableDictionary dictionary]; NSArray *reversedItems = [[_sceneModel.layers reverseObjectEnumerator] allObjects]; - + + LALayerView *maskedLayer = nil; for (LALayer *layer in reversedItems) { LALayerView *layerView = [[LALayerView alloc] initWithModel:layer inComposition:_sceneModel]; layerMap[layer.layerID] = layerView; - [self.layer addSublayer:layerView]; + if (maskedLayer) { + maskedLayer.mask = layerView; + maskedLayer = nil; + } else { + if (layer.matteType == LAMatteTypeAdd) { + maskedLayer = layerView; + } + [self.layer addSublayer:layerView]; + } } _layerMap = layerMap; } diff --git a/LotteAnimator/LAEllipseShapeLayer.h b/LotteAnimator/LAEllipseShapeLayer.h new file mode 100644 index 0000000000..7914cfcad7 --- /dev/null +++ b/LotteAnimator/LAEllipseShapeLayer.h @@ -0,0 +1,20 @@ +// +// LAEllipseShapeLayer.h +// LotteAnimator +// +// Created by brandon_withrow on 7/26/16. +// Copyright © 2016 Brandon Withrow. All rights reserved. +// + +#import "LAAnimatableLayer.h" + +@interface LAEllipseShapeLayer : LAAnimatableLayer + +- (instancetype)initWithEllipseShape:(LAShapeCircle *)circleShape + fill:(LAShapeFill *)fill + stroke:(LAShapeStroke *)stroke + trim:(LAShapeTrimPath *)trim + transform:(LAShapeTransform *)transform + withDuration:(NSTimeInterval)duration; + +@end diff --git a/LotteAnimator/LAEllipseShapeLayer.m b/LotteAnimator/LAEllipseShapeLayer.m new file mode 100644 index 0000000000..89aacc98e4 --- /dev/null +++ b/LotteAnimator/LAEllipseShapeLayer.m @@ -0,0 +1,121 @@ +// +// LAEllipseShapeLayer.m +// LotteAnimator +// +// Created by brandon_withrow on 7/26/16. +// Copyright © 2016 Brandon Withrow. All rights reserved. +// + +#import "LAEllipseShapeLayer.h" +#import "CAAnimationGroup+LAAnimatableGroup.h" + +@implementation LAEllipseShapeLayer { + LAShapeTransform *_transform; + LAShapeStroke *_stroke; + LAShapeFill *_fill; + LAShapeCircle *_circle; + LAShapeTrimPath *_trim; + + CAShapeLayer *_fillLayer; + CAShapeLayer *_strokeLayer; + + CAAnimationGroup *_animation; + CAAnimationGroup *_strokeAnimation; + CAAnimationGroup *_fillAnimation; +} + +- (instancetype)initWithEllipseShape:(LAShapeCircle *)circleShape + fill:(LAShapeFill *)fill + stroke:(LAShapeStroke *)stroke + trim:(LAShapeTrimPath *)trim + transform:(LAShapeTransform *)transform + withDuration:(NSTimeInterval)duration { + self = [super initWithDuration:duration]; + if (self) { + _circle = circleShape; + _stroke = stroke; + _fill = fill; + _transform = transform; + _trim = trim; + + self.allowsEdgeAntialiasing = YES; + self.frame = _transform.compBounds; + self.anchorPoint = _transform.anchor.initialPoint; + self.opacity = _transform.opacity.initialValue.floatValue; + self.position = _transform.position.initialPoint; + self.transform = _transform.scale.initialScale; + self.sublayerTransform = CATransform3DMakeRotation(_transform.rotation.initialValue.floatValue, 0, 0, 1); + + if (fill) { + _fillLayer = [CAShapeLayer new]; + _fillLayer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-50, -50, 100, 100)].CGPath; + _fillLayer.allowsEdgeAntialiasing = YES; + _fillLayer.position = circleShape.position.initialPoint; + _fillLayer.transform = circleShape.scale.initialScale; + _fillLayer.fillColor = _fill.color.initialColor.CGColor; + _fillLayer.opacity = _fill.opacity.initialValue.floatValue; + [self addSublayer:_fillLayer]; + } + + if (stroke) { + _strokeLayer = [CAShapeLayer new]; + _strokeLayer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-50, -50, 100, 100)].CGPath; + _strokeLayer.allowsEdgeAntialiasing = YES; + _strokeLayer.position = circleShape.position.initialPoint; + _strokeLayer.transform = circleShape.scale.initialScale; + _strokeLayer.strokeColor = _stroke.color.initialColor.CGColor; + _strokeLayer.opacity = _stroke.opacity.initialValue.floatValue; + _strokeLayer.lineWidth = _stroke.width.initialValue.floatValue; + _strokeLayer.fillColor = nil; + _strokeLayer.backgroundColor = nil; + _strokeLayer.lineDashPattern = _stroke.lineDashPattern; + if (trim) { + _strokeLayer.strokeStart = _trim.start.initialValue.floatValue; + _strokeLayer.strokeEnd = _trim.end.initialValue.floatValue; + } + [self addSublayer:_strokeLayer]; + } + self.animationSublayers = [NSArray arrayWithArray:self.sublayers]; + + [self _buildAnimation]; + [self pause]; + } + + return self; +} + +- (void)_buildAnimation { + if (_transform) { + _animation = [CAAnimationGroup animationGroupForAnimatablePropertiesWithKeyPaths:@{@"opacity" : _transform.opacity, + @"position" : _transform.position, + @"anchorPoint" : _transform.anchor, + @"transform" : _transform.scale, + @"sublayerTransform.rotation" : _transform.rotation}]; + [self addAnimation:_animation forKey:@"LotteAnimation"]; + } + + if (_stroke) { + NSMutableDictionary *properties = [NSMutableDictionary dictionaryWithDictionary:@{@"strokeColor" : _stroke.color, + @"opacity" : _stroke.opacity, + @"lineWidth" : _stroke.width, + @"position" : _circle.position, + @"transform" : _circle.scale}]; + if (_trim) { + properties[@"strokeStart"] = _trim.start; + properties[@"strokeEnd"] = _trim.end; + } + _strokeAnimation = [CAAnimationGroup animationGroupForAnimatablePropertiesWithKeyPaths:properties]; + [_strokeLayer addAnimation:_strokeAnimation forKey:@""]; + + } + + if (_fill) { + _fillAnimation = [CAAnimationGroup animationGroupForAnimatablePropertiesWithKeyPaths:@{@"backgroundColor" : _fill.color, + @"opacity" : _fill.opacity, + @"position" : _circle.position, + @"transform" : _circle.scale}]; + [_fillLayer addAnimation:_fillAnimation forKey:@""]; + } +} + +@end diff --git a/LotteAnimator/LAGroupLayerView.m b/LotteAnimator/LAGroupLayerView.m index 5485d45f19..354a8f5212 100644 --- a/LotteAnimator/LAGroupLayerView.m +++ b/LotteAnimator/LAGroupLayerView.m @@ -9,6 +9,8 @@ #import "LAGroupLayerView.h" #import "LAShapeLayerView.h" #import "LARectShapeLayer.h" +#import "LAEllipseShapeLayer.h" + #import "CAAnimationGroup+LAAnimatableGroup.h" @implementation LAGroupLayerView { @@ -45,6 +47,7 @@ LAShapeFill *currentFill; LAShapeStroke *currentStroke; LAShapeTransform *currentTransform; + LAShapeTrimPath *currentTrim; NSMutableArray *shapeLayers = [NSMutableArray array]; NSMutableArray *groupLayers = [NSMutableArray array]; @@ -56,11 +59,14 @@ currentStroke = item; } else if ([item isKindOfClass:[LAShapeFill class]]) { currentFill = item; + } else if ([item isKindOfClass:[LAShapeTrimPath class]]) { + currentTrim = item; } else if ([item isKindOfClass:[LAShapePath class]]) { LAShapePath *shapePath = (LAShapePath *)item; LAShapeLayerView *shapeLayer = [[LAShapeLayerView alloc] initWithShape:shapePath fill:currentFill stroke:currentStroke + trim:currentTrim transform:currentTransform withDuration:self.laAnimationDuration]; [shapeLayers addObject:shapeLayer]; @@ -74,6 +80,16 @@ withDuration:self.laAnimationDuration]; [shapeLayers addObject:shapeLayer]; [self addSublayer:shapeLayer]; + } else if ([item isKindOfClass:[LAShapeCircle class]]) { + LAShapeCircle *shapeCircle = (LAShapeCircle *)item; + LAEllipseShapeLayer *shapeLayer = [[LAEllipseShapeLayer alloc] initWithEllipseShape:shapeCircle + fill:currentFill + stroke:currentStroke + trim:currentTrim + transform:currentTransform + withDuration:self.laAnimationDuration]; + [shapeLayers addObject:shapeLayer]; + [self addSublayer:shapeLayer]; } else if ([item isKindOfClass:[LAShapeGroup class]]) { LAShapeGroup *shapeGroup = (LAShapeGroup *)item; LAGroupLayerView *groupLayer = [[LAGroupLayerView alloc] initWithShapeGroup:shapeGroup diff --git a/LotteAnimator/LALayer.h b/LotteAnimator/LALayer.h index ce5e1cfebe..d7faa3627b 100644 --- a/LotteAnimator/LALayer.h +++ b/LotteAnimator/LALayer.h @@ -14,7 +14,6 @@ @class LAAnimatableColorValue; @class LAAnimatablePointValue; @class LAAnimatableNumberValue; -@class LAAnimatableRectValue; @class LAAnimatableScaleValue; @class LAComposition; @@ -26,6 +25,13 @@ typedef enum : NSInteger { LALayerTypeShape } LALayerType; +typedef enum : NSInteger { + LAMatteTypeNone, + LAMatteTypeAdd, + LAMatteTypeInvert, + LALayerTypeUknown +} LAMatteType; + @interface LALayer : NSObject - (instancetype)initWithJSON:(NSDictionary *)jsonDictionary fromComposition:(LAComposition *)composition; @@ -42,8 +48,9 @@ typedef enum : NSInteger { @property (nonatomic, readonly) NSArray *shapes; @property (nonatomic, readonly) NSArray *masks; -@property (nonatomic, readonly) LAAnimatableRectValue *solidBounds; -@property (nonatomic, readonly) LAAnimatableColorValue *solidColor; +@property (nonatomic, readonly) NSNumber *solidWidth; +@property (nonatomic, readonly) NSNumber *solidHeight; +@property (nonatomic, readonly) UIColor *solidColor; @property (nonatomic, readonly) LAAnimatableNumberValue *opacity; @property (nonatomic, readonly) LAAnimatableNumberValue *rotation; @@ -59,4 +66,6 @@ typedef enum : NSInteger { @property (nonatomic, readonly) NSArray *inOutKeyTimes; @property (nonatomic, readonly) NSTimeInterval compDuration; +@property (nonatomic, readonly) LAMatteType matteType; + @end diff --git a/LotteAnimator/LALayer.m b/LotteAnimator/LALayer.m index 3ec1c1d0fe..2d6767623d 100644 --- a/LotteAnimator/LALayer.m +++ b/LotteAnimator/LALayer.m @@ -42,8 +42,10 @@ _outFrame = [jsonDictionary[@"op"] copy]; if (_layerType == LALayerTypeSolid) { - // TODO Solids. - + _solidWidth = jsonDictionary[@"sw"]; + _solidHeight = jsonDictionary[@"sh"]; + NSString *solidColor = jsonDictionary[@"sc"]; + _solidColor = [UIColor colorWithHexString:solidColor]; } NSDictionary *ks = jsonDictionary[@"ks"]; @@ -78,6 +80,9 @@ _scale = [[LAAnimatableScaleValue alloc] initWithScaleValues:scale frameRate:_framerate]; } + _matteType = [jsonDictionary[@"tt"] integerValue]; + + NSMutableArray *masks = [NSMutableArray array]; for (NSDictionary *maskJSON in jsonDictionary[@"masksProperties"]) { LAMask *mask = [[LAMask alloc] initWithJSON:maskJSON frameRate:_framerate]; diff --git a/LotteAnimator/LALayerView.m b/LotteAnimator/LALayerView.m index 48401872b4..8163696812 100644 --- a/LotteAnimator/LALayerView.m +++ b/LotteAnimator/LALayerView.m @@ -10,6 +10,7 @@ #import "LAShapeLayerView.h" #import "LAGroupLayerView.h" #import "CAAnimationGroup+LAAnimatableGroup.h" +#import "LAMaskLayer.h" @interface LAParentLayer : LAAnimatableLayer @@ -59,7 +60,7 @@ CAKeyframeAnimation *_inOutAnimation; NSArray *_parentLayers; LAComposition *_composition; - + LAMaskLayer *_maskLayer; } - (instancetype)initWithModel:(LALayer *)model inComposition:(LAComposition *)comp { @@ -73,9 +74,18 @@ } - (void)_setupViewFromModel { - self.bounds = _composition.compBounds; + self.backgroundColor = nil; + if (_layerModel.layerType == LALayerTypeSolid) { + self.bounds = CGRectMake(0, 0, _layerModel.solidWidth.floatValue, _layerModel.solidHeight.floatValue); + } else { + self.bounds = _composition.compBounds; + } + self.anchorPoint = CGPointZero; + _childContainerLayer = [CALayer new]; + _childContainerLayer.bounds = self.bounds; + _childContainerLayer.backgroundColor = _layerModel.solidColor.CGColor; self.animationSublayers = @[_childContainerLayer]; NSNumber *parentID = _layerModel.parentID; @@ -121,9 +131,29 @@ _shapeLayers = shapeLayers; +// CALayer *anchorLayer = [CALayer new]; +// anchorLayer.bounds = CGRectMake(0, 0, 20, 20); +// anchorLayer.backgroundColor = [UIColor redColor].CGColor; +// anchorLayer.anchorPoint = CGPointMake(0.5, 0.5); +// anchorLayer.position = CGPointZero; +// anchorLayer.opacity = 0.25; +// _childContainerLayer.borderWidth = 6; +// _childContainerLayer.backgroundColor = [UIColor greenColor].CGColor; +// _childContainerLayer.borderColor = [UIColor redColor].CGColor; +// [_childContainerLayer addSublayer:anchorLayer]; + + if (_layerModel.masks) { + _maskLayer = [[LAMaskLayer alloc] initWithMasks:_layerModel.masks inComposition:_composition]; + _maskLayer.opacity = 0.5; + [_childContainerLayer addSublayer:_maskLayer]; + } + NSMutableArray *childLayers = [NSMutableArray array]; [childLayers addObjectsFromArray:_parentLayers]; [childLayers addObjectsFromArray:_shapeLayers]; + if (_maskLayer) { + [childLayers addObject:_maskLayer]; + } self.childLayers = childLayers; [self _buildAnimations]; diff --git a/LotteAnimator/LAMaskLayer.m b/LotteAnimator/LAMaskLayer.m index 7597656564..291f25ec67 100644 --- a/LotteAnimator/LAMaskLayer.m +++ b/LotteAnimator/LAMaskLayer.m @@ -7,14 +7,17 @@ // #import "LAMaskLayer.h" +#import "CAAnimationGroup+LAAnimatableGroup.h" @implementation LAMaskLayer { LAComposition *_composition; + NSArray *_maskLayers; } - (instancetype)initWithMasks:(NSArray *)masks inComposition:(LAComposition *)comp { self = [super initWithDuration:comp.timeDuration]; if (self) { +// self.bounds = comp.compBounds; _masks = masks; _composition = comp; [self _setupViewFromModel]; @@ -23,6 +26,31 @@ } - (void)_setupViewFromModel { + NSMutableArray *maskLayers = [NSMutableArray array]; + + for (LAMask *mask in _masks) { + CAShapeLayer *maskLayer = [CAShapeLayer new]; + maskLayer.path = mask.maskPath.initialShape.CGPath; + maskLayer.fillColor = [UIColor whiteColor].CGColor; + maskLayer.opacity = mask.opacity.initialValue.floatValue; + [self addSublayer:maskLayer]; + CAAnimationGroup *animGroup = [CAAnimationGroup animationGroupForAnimatablePropertiesWithKeyPaths:@{@"opacity" : mask.opacity, + @"path" : mask.maskPath}]; + if (animGroup) { + [maskLayer addAnimation:animGroup forKey:@""]; + } + [maskLayers addObject:maskLayer]; + } + _maskLayers = maskLayers; + self.animationSublayers = maskLayers; + [self pause]; +} + +- (void)drawInContext:(CGContextRef)ctx { + +} + +-(void)renderInContext:(CGContextRef)ctx { } diff --git a/LotteAnimator/LAModels.h b/LotteAnimator/LAModels.h index 629b3c281e..1911d44004 100644 --- a/LotteAnimator/LAModels.h +++ b/LotteAnimator/LAModels.h @@ -22,9 +22,9 @@ #import "LAAnimatableColorValue.h" #import "LAAnimatableNumberValue.h" #import "LAAnimatablePointValue.h" -#import "LAAnimatableRectValue.h" #import "LAAnimatableScaleValue.h" #import "LAAnimatableShapeValue.h" +#import "LAShapeTrimPath.h" #endif /* LAModels_h */ diff --git a/LotteAnimator/LARectShapeLayer.h b/LotteAnimator/LARectShapeLayer.h index 7dd331635e..813f3f2949 100644 --- a/LotteAnimator/LARectShapeLayer.h +++ b/LotteAnimator/LARectShapeLayer.h @@ -12,9 +12,9 @@ @interface LARectShapeLayer : LAAnimatableLayer - (instancetype)initWithRectShape:(LAShapeRectangle *)rectShape - fill:(LAShapeFill *)fill - stroke:(LAShapeStroke *)stroke - transform:(LAShapeTransform *)transform + fill:(LAShapeFill *)fill + stroke:(LAShapeStroke *)stroke + transform:(LAShapeTransform *)transform withDuration:(NSTimeInterval)duration; @end diff --git a/LotteAnimator/LARectShapeLayer.m b/LotteAnimator/LARectShapeLayer.m index c1a7a5c7d2..d9abab4589 100644 --- a/LotteAnimator/LARectShapeLayer.m +++ b/LotteAnimator/LARectShapeLayer.m @@ -43,24 +43,30 @@ self.transform = _transform.scale.initialScale; self.sublayerTransform = CATransform3DMakeRotation(_transform.rotation.initialValue.floatValue, 0, 0, 1); - _fillLayer = [CALayer layer]; - _fillLayer.allowsEdgeAntialiasing = YES; - _fillLayer.bounds = rectShape.bounds.initialBounds; - _fillLayer.position = rectShape.position.initialPoint; - _fillLayer.cornerRadius = rectShape.cornerRadius.initialValue.floatValue; - _fillLayer.backgroundColor = _fill.color.initialColor.CGColor; - _fillLayer.opacity = _fill.opacity.initialValue.floatValue; - [self addSublayer:_fillLayer]; + if (fill) { + _fillLayer = [CALayer layer]; + _fillLayer.allowsEdgeAntialiasing = YES; + _fillLayer.bounds = rectShape.bounds.initialBounds; + _fillLayer.position = rectShape.position.initialPoint; + _fillLayer.cornerRadius = rectShape.cornerRadius.initialValue.floatValue; + _fillLayer.backgroundColor = _fill.color.initialColor.CGColor; + _fillLayer.opacity = _fill.opacity.initialValue.floatValue; + [self addSublayer:_fillLayer]; + } + + if (stroke) { + _strokeLayer = [CALayer layer]; + _strokeLayer.allowsEdgeAntialiasing = YES; + _strokeLayer.bounds = rectShape.bounds.initialBounds; + _strokeLayer.position = rectShape.position.initialPoint; + _strokeLayer.cornerRadius = rectShape.cornerRadius.initialValue.floatValue; + _strokeLayer.borderColor = _stroke.color.initialColor.CGColor; + _strokeLayer.opacity = _stroke.opacity.initialValue.floatValue; + _strokeLayer.borderWidth = _stroke.width.initialValue.floatValue; + _strokeLayer.backgroundColor = nil; + } + self.animationSublayers = [NSArray arrayWithArray:self.sublayers]; - _strokeLayer = [CALayer layer]; - _strokeLayer.allowsEdgeAntialiasing = YES; - _strokeLayer.bounds = rectShape.bounds.initialBounds; - _strokeLayer.position = rectShape.position.initialPoint; - _strokeLayer.cornerRadius = rectShape.cornerRadius.initialValue.floatValue; - _strokeLayer.borderColor = _stroke.color.initialColor.CGColor; - _strokeLayer.opacity = _stroke.opacity.initialValue.floatValue; - _strokeLayer.borderWidth = _stroke.width.initialValue.floatValue; - _strokeLayer.backgroundColor = nil; [self addSublayer:_strokeLayer]; [self _buildAnimation]; [self pause]; diff --git a/LotteAnimator/LAShapeCircle.h b/LotteAnimator/LAShapeCircle.h index 8421f50b6d..4347837415 100644 --- a/LotteAnimator/LAShapeCircle.h +++ b/LotteAnimator/LAShapeCircle.h @@ -12,4 +12,7 @@ - (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate; +@property (nonatomic, readonly) LAAnimatablePointValue *position; +@property (nonatomic, readonly) LAAnimatableScaleValue *scale; + @end diff --git a/LotteAnimator/LAShapeCircle.m b/LotteAnimator/LAShapeCircle.m index ef4ec4168f..32b3286df3 100644 --- a/LotteAnimator/LAShapeCircle.m +++ b/LotteAnimator/LAShapeCircle.m @@ -19,7 +19,16 @@ } - (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + NSDictionary *position = jsonDictionary[@"p"]; + if (position) { + _position = [[LAAnimatablePointValue alloc] initWithPointValues:position frameRate:frameRate]; + _position.usePathAnimation = NO; + } + NSDictionary *scale = jsonDictionary[@"s"]; + if (scale) { + _scale = [[LAAnimatableScaleValue alloc] initWithScaleValues:scale frameRate:frameRate]; + } } @end diff --git a/LotteAnimator/LAShapeGroup.m b/LotteAnimator/LAShapeGroup.m index f68d041480..d122c0f572 100644 --- a/LotteAnimator/LAShapeGroup.m +++ b/LotteAnimator/LAShapeGroup.m @@ -13,6 +13,7 @@ #import "LAShapeStroke.h" #import "LAShapeTransform.h" #import "LAShapeRectangle.h" +#import "LAShapeTrimPath.h" @implementation LAShapeGroup @@ -51,6 +52,9 @@ } else if ([type isEqualToString:@"rc"]) { LAShapeRectangle *rectangle = [[LAShapeRectangle alloc] initWithJSON:itemJSON frameRate:frameRate]; [items addObject:rectangle]; + } else if ([type isEqualToString:@"tm"]) { + LAShapeTrimPath *trim = [[LAShapeTrimPath alloc] initWithJSON:itemJSON frameRate:frameRate]; + [items addObject:trim]; } } _items = items; diff --git a/LotteAnimator/LAShapeLayerView.h b/LotteAnimator/LAShapeLayerView.h index 0cb38abe38..638194ef10 100644 --- a/LotteAnimator/LAShapeLayerView.h +++ b/LotteAnimator/LAShapeLayerView.h @@ -14,9 +14,8 @@ - (instancetype)initWithShape:(LAShapePath *)shape fill:(LAShapeFill *)fill stroke:(LAShapeStroke *)stroke + trim:(LAShapeTrimPath *)trim transform:(LAShapeTransform *)transform withDuration:(NSTimeInterval)duration; -- (void)startAnimation; - @end diff --git a/LotteAnimator/LAShapeLayerView.m b/LotteAnimator/LAShapeLayerView.m index 2d7ec48720..34374c9a94 100644 --- a/LotteAnimator/LAShapeLayerView.m +++ b/LotteAnimator/LAShapeLayerView.m @@ -14,6 +14,7 @@ LAShapeStroke *_stroke; LAShapeFill *_fill; LAShapePath *_path; + LAShapeTrimPath *_trim; CAShapeLayer *_fillLayer; CAShapeLayer *_strokeLayer; @@ -26,6 +27,7 @@ - (instancetype)initWithShape:(LAShapePath *)shape fill:(LAShapeFill *)fill stroke:(LAShapeStroke *)stroke + trim:(LAShapeTrimPath *)trim transform:(LAShapeTransform *)transform withDuration:(NSTimeInterval)duration { self = [super initWithDuration:duration]; @@ -34,6 +36,7 @@ _stroke = stroke; _fill = fill; _transform = transform; + _trim = trim; self.allowsEdgeAntialiasing = YES; self.frame = _transform.compBounds; @@ -43,26 +46,43 @@ self.transform = _transform.scale.initialScale; self.sublayerTransform = CATransform3DMakeRotation(_transform.rotation.initialValue.floatValue, 0, 0, 1); - _fillLayer = [CAShapeLayer layer]; - _fillLayer.allowsEdgeAntialiasing = YES; - _fillLayer.path = _path.shapePath.initialShape.CGPath; - _fillLayer.fillColor = _fill.color.initialColor.CGColor; - _fillLayer.opacity = _fill.opacity.initialValue.floatValue; - [self addSublayer:_fillLayer]; + if (fill) { + _fillLayer = [CAShapeLayer layer]; + _fillLayer.allowsEdgeAntialiasing = YES; + _fillLayer.path = _path.shapePath.initialShape.CGPath; + _fillLayer.fillColor = _fill.color.initialColor.CGColor; + _fillLayer.opacity = _fill.opacity.initialValue.floatValue; + [self addSublayer:_fillLayer]; + } - _strokeLayer = [CAShapeLayer layer]; - _strokeLayer.allowsEdgeAntialiasing = YES; - _strokeLayer.path = _path.shapePath.initialShape.CGPath; - _strokeLayer.strokeColor = _stroke.color.initialColor.CGColor; - _strokeLayer.opacity = _stroke.opacity.initialValue.floatValue; - _strokeLayer.lineWidth = _stroke.width.initialValue.floatValue; - _strokeLayer.fillColor = nil; - self.animationSublayers = @[_fillLayer, _strokeLayer]; + if (stroke) { + _strokeLayer = [CAShapeLayer layer]; + _strokeLayer.allowsEdgeAntialiasing = YES; + _strokeLayer.path = _path.shapePath.initialShape.CGPath; + _strokeLayer.strokeColor = _stroke.color.initialColor.CGColor; + _strokeLayer.opacity = _stroke.opacity.initialValue.floatValue; + _strokeLayer.lineWidth = _stroke.width.initialValue.floatValue; + _strokeLayer.lineDashPattern = _stroke.lineDashPattern; + if (trim) { + _strokeLayer.strokeStart = _trim.start.initialValue.floatValue; + _strokeLayer.strokeEnd = _trim.end.initialValue.floatValue; + } + _strokeLayer.fillColor = nil; + } + + self.animationSublayers = [NSArray arrayWithArray:self.sublayers]; [self addSublayer:_strokeLayer]; [self _buildAnimation]; [self pause]; - +// CALayer *anchorLayer = [CALayer new]; +// anchorLayer.bounds = CGRectMake(0, 0, 10, 10); +// anchorLayer.backgroundColor = [UIColor blueColor].CGColor; +// anchorLayer.anchorPoint = CGPointMake(0.5, 0.5); +// anchorLayer.position = CGPointZero; +// self.borderColor = [UIColor blueColor].CGColor; +// self.borderWidth = 2; +// [self addSublayer:anchorLayer]; } return self; } @@ -78,10 +98,15 @@ } if (_stroke) { - _strokeAnimation = [CAAnimationGroup animationGroupForAnimatablePropertiesWithKeyPaths:@{@"strokeColor" : _stroke.color, - @"opacity" : _stroke.opacity, - @"lineWidth" : _stroke.width, - @"path" : _path.shapePath}]; + NSMutableDictionary *properties = [NSMutableDictionary dictionaryWithDictionary:@{@"strokeColor" : _stroke.color, + @"opacity" : _stroke.opacity, + @"lineWidth" : _stroke.width, + @"path" : _path.shapePath}]; + if (_trim) { + properties[@"strokeStart"] = _trim.start; + properties[@"strokeEnd"] = _trim.end; + } + _strokeAnimation = [CAAnimationGroup animationGroupForAnimatablePropertiesWithKeyPaths:properties]; [_strokeLayer addAnimation:_strokeAnimation forKey:@""]; } diff --git a/LotteAnimator/LAShapeStroke.h b/LotteAnimator/LAShapeStroke.h index f795df4cae..e181885ac6 100644 --- a/LotteAnimator/LAShapeStroke.h +++ b/LotteAnimator/LAShapeStroke.h @@ -19,5 +19,6 @@ @property (nonatomic, readonly) LAAnimatableColorValue *color; @property (nonatomic, readonly) LAAnimatableNumberValue *opacity; @property (nonatomic, readonly) LAAnimatableNumberValue *width; +@property (nonatomic, readonly) NSArray *lineDashPattern; @end diff --git a/LotteAnimator/LAShapeStroke.m b/LotteAnimator/LAShapeStroke.m index 299b2492e7..54410368b9 100644 --- a/LotteAnimator/LAShapeStroke.m +++ b/LotteAnimator/LAShapeStroke.m @@ -39,6 +39,20 @@ NSNumber *fillEnabled = jsonDictionary[@"fillEnabled"]; _fillEnabled = fillEnabled.boolValue; + + NSArray *dashes = jsonDictionary[@"d"]; + if (dashes) { + NSMutableArray *dashPattern = [NSMutableArray array]; + for (NSDictionary *dash in dashes) { + if ([dash[@"n"] isEqualToString:@"o"]) { + continue; + } + NSDictionary *value = dash[@"v"]; + LAAnimatableNumberValue *numberValue = [[LAAnimatableNumberValue alloc] initWithNumberValues:value frameRate:frameRate]; + [dashPattern addObject:[numberValue.initialValue copy]]; + } + _lineDashPattern = dashPattern; + } } @end diff --git a/LotteAnimator/LAShapeTrimPath.h b/LotteAnimator/LAShapeTrimPath.h new file mode 100644 index 0000000000..7e4d134bf7 --- /dev/null +++ b/LotteAnimator/LAShapeTrimPath.h @@ -0,0 +1,19 @@ +// +// LAShapeTrimPath.h +// LotteAnimator +// +// Created by brandon_withrow on 7/26/16. +// Copyright © 2016 Brandon Withrow. All rights reserved. +// + +#import +@class LAAnimatableNumberValue; + +@interface LAShapeTrimPath : NSObject + +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate; + +@property (nonatomic, readonly) LAAnimatableNumberValue *start; +@property (nonatomic, readonly) LAAnimatableNumberValue *end; + +@end diff --git a/LotteAnimator/LAShapeTrimPath.m b/LotteAnimator/LAShapeTrimPath.m new file mode 100644 index 0000000000..6665548fe5 --- /dev/null +++ b/LotteAnimator/LAShapeTrimPath.m @@ -0,0 +1,35 @@ +// +// LAShapeTrimPath.m +// LotteAnimator +// +// Created by brandon_withrow on 7/26/16. +// Copyright © 2016 Brandon Withrow. All rights reserved. +// + +#import "LAShapeTrimPath.h" + +@implementation LAShapeTrimPath + +- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + self = [super init]; + if (self) { + [self _mapFromJSON:jsonDictionary frameRate:frameRate]; + } + return self; +} + +- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate { + NSDictionary *start = jsonDictionary[@"s"]; + if (start) { + _start = [[LAAnimatableNumberValue alloc] initWithNumberValues:start frameRate:frameRate]; + [_start remapValuesFromMin:@0 fromMax:@100 toMin:@0 toMax:@1]; + } + + NSDictionary *end = jsonDictionary[@"e"]; + if (end) { + _end = [[LAAnimatableNumberValue alloc] initWithNumberValues:end frameRate:frameRate]; + [_end remapValuesFromMin:@0 fromMax:@100 toMin:@0 toMax:@1]; + } +} + +@end diff --git a/LotteAnimator/UIColor+Expanded.m b/LotteAnimator/UIColor+Expanded.m index d735570f2a..513f7b983c 100644 --- a/LotteAnimator/UIColor+Expanded.m +++ b/LotteAnimator/UIColor+Expanded.m @@ -359,7 +359,8 @@ static NSMutableDictionary *colorNameCache = nil; // Returns a UIColor by scanning the string for a hex number and passing that to +[UIColor colorWithRGBHex:] // Skips any leading whitespace and ignores any trailing characters + (UIColor *)colorWithHexString:(NSString *)stringToConvert { - NSScanner *scanner = [NSScanner scannerWithString:stringToConvert]; + NSString *strippedString = [stringToConvert stringByReplacingOccurrencesOfString:@"#" withString:@""]; + NSScanner *scanner = [NSScanner scannerWithString:strippedString]; unsigned hexNum; if (![scanner scanHexInt:&hexNum]) return nil; return [UIColor colorWithRGBHex:hexNum]; diff --git a/LotteAnimator/circleTest.json b/LotteAnimator/circleTest.json new file mode 100644 index 0000000000..3299d1324c --- /dev/null +++ b/LotteAnimator/circleTest.json @@ -0,0 +1 @@ +{"assets":[],"v":"4.1.7","ddd":0,"layers":[{"ddd":0,"ind":0,"ty":4,"nm":"Shape Layer 2","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[300,300,0]},"a":{"k":[0,0,0]},"s":{"k":[100,247.571,100]}},"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s":[140.039,147.461],"e":[28.039,29.525],"__fnct":[null,null]},{"t":98}]},"p":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[0,0],"e":[-87,69],"to":[-14.5,11.5],"ti":[14.5,-11.5]},{"t":98}]},"nm":"Ellipse Path 1","closed":true},{"d":1,"ty":"el","s":{"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s":[140.039,147.461],"e":[28.039,29.525],"__fnct":[null,null]},{"t":98}]},"p":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[0,0],"e":[-87,69],"to":[-14.5,11.5],"ti":[14.5,-11.5]},{"t":98}]},"nm":"Ellipse Path 1","closed":true},{"ty":"st","fillEnabled":true,"c":{"k":[255,255,255,255]},"o":{"k":100},"w":{"k":2},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[255,255,255,255]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[48.98,-45.27]},"a":{"k":[0,0]},"s":{"k":[100,100]},"r":{"k":0},"o":{"k":100},"sk":{"k":0},"sa":{"k":0}}],"nm":"Ellipse 1"}],"bounds":{"l":-121,"t":-147,"b":95,"r":146},"ip":0,"op":180,"st":0},{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[300,300,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"k":[200,200]},"p":{"k":[0,0]},"nm":"Ellipse Path 1","closed":true},{"d":1,"ty":"el","s":{"k":[200,200]},"p":{"k":[0,0]},"nm":"Ellipse Path 1","closed":true},{"ty":"st","fillEnabled":true,"c":{"k":[255,255,255,255]},"o":{"k":100},"w":{"k":2},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[201,26,26,255]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"r":{"k":0},"o":{"k":100},"sk":{"k":0},"sa":{"k":0}}],"nm":"Ellipse 1"}],"bounds":{"l":-137,"t":-137,"b":137,"r":137},"ip":0,"op":180,"st":0}],"ip":0,"op":180,"fr":60,"w":600,"h":600} \ No newline at end of file diff --git a/LotteAnimator/masksAndSolids.json b/LotteAnimator/masksAndSolids.json new file mode 100644 index 0000000000..63b9bcb22c --- /dev/null +++ b/LotteAnimator/masksAndSolids.json @@ -0,0 +1 @@ +{"assets":[],"v":"4.1.7","ddd":0,"layers":[{"ddd":0,"ind":0,"ty":4,"nm":"Shape Layer 1","td":1,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[306,300,0]},"a":{"k":[0,0,0]},"s":{"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s":[51.741,51.741,100],"e":[122.667,122.667,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":90,"s":[122.667,122.667,100],"e":[70.07,70.07,100]},{"t":174}]}},"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"k":[275.75,275.75]},"p":{"k":[0,0]},"nm":"Ellipse Path 1","closed":true},{"d":1,"ty":"el","s":{"k":[275.75,275.75]},"p":{"k":[0,0]},"nm":"Ellipse Path 1","closed":true},{"ty":"st","fillEnabled":true,"c":{"k":[255,255,255,255]},"o":{"k":100},"w":{"k":2},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[255,255,255,255]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[-4.789,-1.113]},"a":{"k":[0,0]},"s":{"k":[100,100]},"r":{"k":0},"o":{"k":100},"sk":{"k":0},"sa":{"k":0}}],"nm":"Ellipse 1"}],"bounds":{"l":-193,"t":-189,"b":187,"r":183},"ip":0,"op":180,"st":0},{"ddd":0,"ind":1,"ty":1,"nm":"Cyan Solid 1","tt":2,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[300,300,0]},"a":{"k":[300,300,0]},"s":{"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s":[100,100,100],"e":[59,59,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":90,"s":[59,59,100],"e":[108,108,100]},{"t":174}]}},"sw":600,"sh":600,"sc":"#00ffc7","ip":0,"op":180,"st":0},{"ddd":0,"ind":2,"ty":1,"nm":"Medium Purple Solid 2","td":1,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[300,300,0]},"a":{"k":[300,300,0]},"s":{"k":[100,100,100]}},"sw":600,"sh":600,"sc":"#9f5eff","ip":0,"op":180,"st":0},{"ddd":0,"ind":3,"ty":1,"nm":"Medium Purple Solid 1","tt":1,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[300,300,0]},"a":{"k":[300,300,0]},"s":{"k":[100,100,100]}},"sw":600,"sh":600,"sc":"#9f5eff","ip":0,"op":180,"st":0}],"ip":0,"op":180,"fr":60,"w":600,"h":600} \ No newline at end of file diff --git a/LotteAnimator/masktest.json b/LotteAnimator/masktest.json new file mode 100644 index 0000000000..6c7c047cf1 --- /dev/null +++ b/LotteAnimator/masktest.json @@ -0,0 +1 @@ +{"assets":[],"v":"4.1.7","ddd":0,"layers":[{"ddd":0,"ind":0,"ty":4,"nm":"Shape Layer 1","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[300,300,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"hasMask":true,"masksProperties":[{"cl":true,"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-276,-245],[-201,111.355],[-208.645,-140.645],[30.355,-120]]}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-276,-245],[-253,177.355],[147.355,192.355],[64.355,-153]]}]},{"t":72}]},"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[100]},{"t":30}]},"x":{"k":0},"nm":"Mask 1"},{"cl":true,"inv":false,"mode":"a","pt":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-152,-76],[-149,49.355],[-47.645,42.355],[-46.645,-72]]}},"o":{"k":100},"x":{"k":0},"nm":"Mask 2"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"k":[231.355,231.355]},"p":{"k":[0,0]},"r":{"k":20},"nm":"Rectangle Path 1","closed":true},{"ty":"st","fillEnabled":true,"c":{"k":[255,255,255,255]},"o":{"k":100},"w":{"k":2},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[255,255,255,255]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[-85.322,-4.322]},"a":{"k":[0,0]},"s":{"k":[100,100]},"r":{"k":0},"o":{"k":100},"sk":{"k":0},"sa":{"k":0}}],"nm":"Rectangle 1"}],"bounds":{"l":-277,"t":-196,"b":187,"r":106},"ip":0,"op":180,"st":0}],"ip":0,"op":180,"fr":60,"w":600,"h":600} \ No newline at end of file