Updated Animated properties. Started removing mantle

This commit is contained in:
Brandon Withrow
2016-07-12 16:41:50 -07:00
parent 3c7a366c47
commit cc83ab86f7
46 changed files with 601 additions and 850 deletions

View File

@@ -17,10 +17,8 @@
4804B3191C1F6DEA00DA8AF7 /* LAComposition.m in Sources */ = {isa = PBXBuildFile; fileRef = 4804B3181C1F6DEA00DA8AF7 /* LAComposition.m */; };
4804B31E1C1F757600DA8AF7 /* UIColor+Expanded.m in Sources */ = {isa = PBXBuildFile; fileRef = 4804B31D1C1F757600DA8AF7 /* UIColor+Expanded.m */; };
4804B3211C1F761800DA8AF7 /* BWMath.m in Sources */ = {isa = PBXBuildFile; fileRef = 4804B3201C1F761800DA8AF7 /* BWMath.m */; };
48372A471C1F8B4C00AD0293 /* LAPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A461C1F8B4C00AD0293 /* LAPath.m */; };
48372A4A1C1F8D7D00AD0293 /* LAMask.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A491C1F8D7D00AD0293 /* LAMask.m */; };
48372A4F1C1F99C600AD0293 /* LAShape.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A4E1C1F99C600AD0293 /* LAShape.m */; };
48372A521C20973300AD0293 /* LAShapeItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A511C20973300AD0293 /* LAShapeItem.m */; };
48372A4F1C1F99C600AD0293 /* LAShapeGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A4E1C1F99C600AD0293 /* LAShapeGroup.m */; };
48372A551C209A5F00AD0293 /* LAShapePath.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A541C209A5F00AD0293 /* LAShapePath.m */; };
48372A581C209A6C00AD0293 /* LAShapeStroke.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A571C209A6C00AD0293 /* LAShapeStroke.m */; };
48372A5B1C209A7A00AD0293 /* LAShapeFill.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A5A1C209A7A00AD0293 /* LAShapeFill.m */; };
@@ -76,6 +74,10 @@
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 */; };
620CD7D11D35AB9C00055AD1 /* LALayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4804B32B1C1F835F00DA8AF7 /* LALayerView.m */; };
620CD7D21D35AB9F00055AD1 /* LACompView.m in Sources */ = {isa = PBXBuildFile; fileRef = 48372A431C1F84D700AD0293 /* LACompView.m */; };
629737DF1D25D7FC007B4AC9 /* allHold_KeyTest.json in Resources */ = {isa = PBXBuildFile; fileRef = 629737DB1D25D7FC007B4AC9 /* allHold_KeyTest.json */; };
629737E01D25D7FC007B4AC9 /* firstHold_KeyTest.json in Resources */ = {isa = PBXBuildFile; fileRef = 629737DC1D25D7FC007B4AC9 /* firstHold_KeyTest.json */; };
629737E11D25D7FC007B4AC9 /* lastHold_KeyTest.json in Resources */ = {isa = PBXBuildFile; fileRef = 629737DD1D25D7FC007B4AC9 /* lastHold_KeyTest.json */; };
@@ -109,14 +111,10 @@
4804B32B1C1F835F00DA8AF7 /* LALayerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LALayerView.m; sourceTree = "<group>"; };
48372A421C1F84D700AD0293 /* LACompView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LACompView.h; sourceTree = "<group>"; };
48372A431C1F84D700AD0293 /* LACompView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LACompView.m; sourceTree = "<group>"; };
48372A451C1F8B4C00AD0293 /* LAPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAPath.h; sourceTree = "<group>"; };
48372A461C1F8B4C00AD0293 /* LAPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAPath.m; sourceTree = "<group>"; };
48372A481C1F8D7D00AD0293 /* LAMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAMask.h; sourceTree = "<group>"; };
48372A491C1F8D7D00AD0293 /* LAMask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAMask.m; sourceTree = "<group>"; };
48372A4D1C1F99C600AD0293 /* LAShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAShape.h; sourceTree = "<group>"; };
48372A4E1C1F99C600AD0293 /* LAShape.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAShape.m; sourceTree = "<group>"; };
48372A501C20973300AD0293 /* LAShapeItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAShapeItem.h; sourceTree = "<group>"; };
48372A511C20973300AD0293 /* LAShapeItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAShapeItem.m; sourceTree = "<group>"; };
48372A4D1C1F99C600AD0293 /* LAShapeGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAShapeGroup.h; sourceTree = "<group>"; };
48372A4E1C1F99C600AD0293 /* LAShapeGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAShapeGroup.m; sourceTree = "<group>"; };
48372A531C209A5F00AD0293 /* LAShapePath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAShapePath.h; sourceTree = "<group>"; };
48372A541C209A5F00AD0293 /* LAShapePath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAShapePath.m; sourceTree = "<group>"; };
48372A561C209A6C00AD0293 /* LAShapeStroke.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAShapeStroke.h; sourceTree = "<group>"; };
@@ -176,7 +174,6 @@
4872BEDB1D146D850028E0B3 /* animatedTransformHold.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = animatedTransformHold.json; sourceTree = "<group>"; };
4872BEDD1D146D850028E0B3 /* animatedTransform.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = animatedTransform.json; sourceTree = "<group>"; };
488990EC1D08A2A400425189 /* curve.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = curve.json; sourceTree = "<group>"; };
620A56451D1B2D3D0030EBFB /* LAAnimatableValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = LAAnimatableValue.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
620A56481D1B3B150030EBFB /* FullLayerModel_Animation.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = FullLayerModel_Animation.json; sourceTree = "<group>"; };
620A565A1D1C81610030EBFB /* LAAnimatableColorValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAAnimatableColorValue.h; sourceTree = "<group>"; };
620A565B1D1C81610030EBFB /* LAAnimatableColorValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableColorValue.m; sourceTree = "<group>"; };
@@ -186,6 +183,10 @@
620A56611D1C81850030EBFB /* LAAnimatableNumberValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableNumberValue.m; sourceTree = "<group>"; };
620A56631D1C81930030EBFB /* LAAnimatableShapeValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAAnimatableShapeValue.h; sourceTree = "<group>"; };
620A56641D1C81930030EBFB /* LAAnimatableShapeValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableShapeValue.m; sourceTree = "<group>"; };
620CD7CB1D3415F000055AD1 /* LAAnimatableRectValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAAnimatableRectValue.h; sourceTree = "<group>"; };
620CD7CC1D3415F000055AD1 /* LAAnimatableRectValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableRectValue.m; sourceTree = "<group>"; };
620CD7CE1D343A2500055AD1 /* LAAnimatableScaleValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAAnimatableScaleValue.h; sourceTree = "<group>"; };
620CD7CF1D343A2500055AD1 /* LAAnimatableScaleValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAAnimatableScaleValue.m; sourceTree = "<group>"; };
629737DB1D25D7FC007B4AC9 /* allHold_KeyTest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = allHold_KeyTest.json; sourceTree = "<group>"; };
629737DC1D25D7FC007B4AC9 /* firstHold_KeyTest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = firstHold_KeyTest.json; sourceTree = "<group>"; };
629737DD1D25D7FC007B4AC9 /* lastHold_KeyTest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = lastHold_KeyTest.json; sourceTree = "<group>"; };
@@ -281,14 +282,10 @@
4804B3181C1F6DEA00DA8AF7 /* LAComposition.m */,
4804B3141C1F5B2000DA8AF7 /* LALayer.h */,
4804B3151C1F5B2000DA8AF7 /* LALayer.m */,
48372A451C1F8B4C00AD0293 /* LAPath.h */,
48372A461C1F8B4C00AD0293 /* LAPath.m */,
48372A481C1F8D7D00AD0293 /* LAMask.h */,
48372A491C1F8D7D00AD0293 /* LAMask.m */,
48372A4D1C1F99C600AD0293 /* LAShape.h */,
48372A4E1C1F99C600AD0293 /* LAShape.m */,
48372A501C20973300AD0293 /* LAShapeItem.h */,
48372A511C20973300AD0293 /* LAShapeItem.m */,
48372A4D1C1F99C600AD0293 /* LAShapeGroup.h */,
48372A4E1C1F99C600AD0293 /* LAShapeGroup.m */,
48372A561C209A6C00AD0293 /* LAShapeStroke.h */,
48372A571C209A6C00AD0293 /* LAShapeStroke.m */,
48372A591C209A7A00AD0293 /* LAShapeFill.h */,
@@ -371,7 +368,6 @@
62F683871D26EF420088C015 /* AnimatableProperties */ = {
isa = PBXGroup;
children = (
620A56451D1B2D3D0030EBFB /* LAAnimatableValue.h */,
620A565A1D1C81610030EBFB /* LAAnimatableColorValue.h */,
620A565B1D1C81610030EBFB /* LAAnimatableColorValue.m */,
620A565D1D1C81750030EBFB /* LAAnimatablePointValue.h */,
@@ -380,6 +376,10 @@
620A56611D1C81850030EBFB /* LAAnimatableNumberValue.m */,
620A56631D1C81930030EBFB /* LAAnimatableShapeValue.h */,
620A56641D1C81930030EBFB /* LAAnimatableShapeValue.m */,
620CD7CB1D3415F000055AD1 /* LAAnimatableRectValue.h */,
620CD7CC1D3415F000055AD1 /* LAAnimatableRectValue.m */,
620CD7CE1D343A2500055AD1 /* LAAnimatableScaleValue.h */,
620CD7CF1D343A2500055AD1 /* LAAnimatableScaleValue.m */,
);
name = AnimatableProperties;
sourceTree = "<group>";
@@ -563,28 +563,30 @@
buildActionMask = 2147483647;
files = (
4804B31E1C1F757600DA8AF7 /* UIColor+Expanded.m in Sources */,
620CD7D21D35AB9F00055AD1 /* LACompView.m in Sources */,
4804B2FF1C1F55E600DA8AF7 /* ViewController.m in Sources */,
48372A641C20A91C00AD0293 /* LAJSONExplorerViewController.m in Sources */,
620A56651D1C81930030EBFB /* LAAnimatableShapeValue.m in Sources */,
4804B3191C1F6DEA00DA8AF7 /* LAComposition.m in Sources */,
4804B2FC1C1F55E600DA8AF7 /* AppDelegate.m in Sources */,
4804B3211C1F761800DA8AF7 /* BWMath.m in Sources */,
48372A471C1F8B4C00AD0293 /* LAPath.m in Sources */,
48372AB41C20C13700AD0293 /* CGGeometryAdditions.m in Sources */,
620A565F1D1C81750030EBFB /* LAAnimatablePointValue.m in Sources */,
48372A4A1C1F8D7D00AD0293 /* LAMask.m in Sources */,
4804B3161C1F5B2000DA8AF7 /* LALayer.m in Sources */,
48372A521C20973300AD0293 /* LAShapeItem.m in Sources */,
48372A4F1C1F99C600AD0293 /* LAShape.m in Sources */,
48372A4F1C1F99C600AD0293 /* LAShapeGroup.m in Sources */,
48372A581C209A6C00AD0293 /* LAShapeStroke.m in Sources */,
620CD7D11D35AB9C00055AD1 /* LALayerView.m in Sources */,
48372ABA1C20D98200AD0293 /* LAShapeRectangle.m in Sources */,
48372A5B1C209A7A00AD0293 /* LAShapeFill.m in Sources */,
4804B2F91C1F55E600DA8AF7 /* main.m in Sources */,
620A56621D1C81850030EBFB /* LAAnimatableNumberValue.m in Sources */,
48372A551C209A5F00AD0293 /* LAShapePath.m in Sources */,
48372AB71C20D97200AD0293 /* LAShapeCircle.m in Sources */,
620CD7CD1D3415F000055AD1 /* LAAnimatableRectValue.m in Sources */,
620A565C1D1C81610030EBFB /* LAAnimatableColorValue.m in Sources */,
48372A5E1C209A8900AD0293 /* LAShapeTransform.m in Sources */,
620CD7D01D343A2500055AD1 /* LAAnimatableScaleValue.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -29,22 +29,6 @@
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "LotteAnimator/LALayer.m"
timestampString = "489098771.583377"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "51"
endingLineNumber = "51"
landmarkName = "+rotationJSONTransformer"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent

View File

@@ -6,17 +6,18 @@
// Copyright © 2016 Brandon Withrow. All rights reserved.
//
#import "LAAnimatableValue.h"
#import <Foundation/Foundation.h>
@interface LAAnimatableColorValue : NSObject
- (instancetype)initWithColorValues:(NSDictionary *)colorValues;
- (void)prepareAnimationsForKeyPath:(NSString *)keyPath frameRate:(NSNumber *)frameRate;
@property (nonatomic, readonly) UIColor *initialColor;
@property (nonatomic, readonly) NSString *keyPath;
@property (nonatomic, readonly) CAKeyframeAnimation *animation;
@property (nonatomic, readonly) NSArray<UIColor *> *colorKeyframes;
@property (nonatomic, readonly) NSArray<NSNumber *> *keyTimes;
@property (nonatomic, readonly) NSArray<CAMediaTimingFunction *> *timingFunctions;
@property (nonatomic, readonly) NSNumber *startFrame;
@property (nonatomic, readonly) NSNumber *durationFrames;
@end

View File

@@ -9,21 +9,16 @@
#import "LAAnimatableColorValue.h"
@implementation LAAnimatableColorValue
@synthesize animation = _animation;
@synthesize keyPath = _keyPath;
- (instancetype)initWithColorValues:(NSDictionary *)colorValues
keyPath:(NSString *)keyPath
frameRate:(NSNumber *)frameRate {
- (instancetype)initWithColorValues:(NSDictionary *)colorValues {
self = [super init];
if (self) {
_keyPath = [keyPath copy];
NSArray *value = colorValues[@"k"];
if ([value isKindOfClass:[NSArray class]] &&
[[(NSArray *)value firstObject] isKindOfClass:[NSDictionary class]] &&
[(NSDictionary *)[(NSArray *)value firstObject] objectForKey:@"t"]) {
//Keframes
[self _buildAnimationForKeyframes:value keyPath:keyPath frameRate:frameRate];
[self _buildAnimationForKeyframes:value];
} else {
//Single Value, no animation
_initialColor = [[self _colorValueFromArray:value] copy];
@@ -32,23 +27,19 @@
return self;
}
- (void)_buildAnimationForKeyframes:(NSArray<NSDictionary *> *)keyframes
keyPath:(NSString *)keyPath
frameRate:(NSNumber *)frameRate {
- (void)_buildAnimationForKeyframes:(NSArray<NSDictionary *> *)keyframes {
NSMutableArray *keyTimes = [NSMutableArray array];
NSMutableArray *timingFunctions = [NSMutableArray array];
NSMutableArray<UIColor *> *colorValues = [NSMutableArray array];
NSNumber *startFrame = keyframes.firstObject[@"t"];
_startFrame = keyframes.firstObject[@"t"];
NSNumber *endFrame = keyframes.lastObject[@"t"];
NSAssert((startFrame && endFrame && startFrame.integerValue < endFrame.integerValue),
NSAssert((_startFrame && endFrame && _startFrame.integerValue < endFrame.integerValue),
@"Lotte: Keyframe animation has incorrect time values or invalid number of keyframes");
// Calculate time bounds
NSTimeInterval beginTime = startFrame.floatValue / frameRate.floatValue;
NSNumber *durationFrames = @(endFrame.floatValue - startFrame.floatValue);
NSTimeInterval durationTime = durationFrames.floatValue / frameRate.floatValue;
// Calculate time duration
_durationFrames = @(endFrame.floatValue - _startFrame.floatValue);
BOOL addStartValue = YES;
BOOL addTimePadding = NO;
@@ -59,11 +50,11 @@
NSNumber *frame = keyframe[@"t"];
// Calculate percentage value for keyframe.
//CA Animations accept time values of 0-1 as a percentage of animation completed.
NSNumber *timePercentage = @((frame.floatValue - startFrame.floatValue) / durationFrames.floatValue);
NSNumber *timePercentage = @((frame.floatValue - _startFrame.floatValue) / _durationFrames.floatValue);
if (outColor) {
//add out value
[colorValues addObject:(id)[[outColor copy] CGColor]];
[colorValues addObject:[outColor copy]];
[timingFunctions addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
outColor = nil;
}
@@ -75,7 +66,7 @@
if (keyframe == keyframes.firstObject) {
_initialColor = startColor;
}
[colorValues addObject:(id)[[startColor copy] CGColor]];
[colorValues addObject:[startColor copy]];
if (timingFunctions.count) {
[timingFunctions addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
}
@@ -93,7 +84,7 @@
// add end value if present for keyframe
UIColor *endColor = [self _colorValueFromArray:keyframe[@"e"]];
if (endColor) {
[colorValues addObject:(id)[[endColor copy] CGColor]];
[colorValues addObject:[endColor copy]];
/*
* Timing Function for time interpolations between keyframes
* Should be n-1 where n is the number of keyframes
@@ -126,13 +117,9 @@
}
}
_animation = [CAKeyframeAnimation animationWithKeyPath:keyPath];
_animation.values = colorValues;
_animation.keyTimes = keyTimes;
_animation.timingFunctions = timingFunctions;
_animation.beginTime = beginTime;
_animation.duration = durationTime;
_animation.fillMode = kCAFillModeForwards;
_colorKeyframes = colorValues;
_keyTimes = keyTimes;
_timingFunctions = timingFunctions;
}
- (UIColor *)_colorValueFromArray:(NSArray<NSNumber *> *)colorArray {

View File

@@ -6,17 +6,17 @@
// Copyright © 2016 Brandon Withrow. All rights reserved.
//
#import "LAAnimatableValue.h"
#import <Foundation/Foundation.h>
@interface LAAnimatableNumberValue : NSObject
- (instancetype)initWithNumberValues:(NSDictionary *)numberValues
keyPath:(NSString *)keyPath
frameRate:(NSNumber *)frameRate;
- (instancetype)initWithNumberValues:(NSDictionary *)numberValues;
@property (nonatomic, readonly) NSNumber *initialValue;
@property (nonatomic, readonly) NSString *keyPath;
@property (nonatomic, readonly) CAKeyframeAnimation *animation;
@property (nonatomic, readonly) NSArray<NSNumber *> *valueKeyframes;
@property (nonatomic, readonly) NSArray<NSNumber *> *keyTimes;
@property (nonatomic, readonly) NSArray<CAMediaTimingFunction *> *timingFunctions;
@property (nonatomic, readonly) NSNumber *startFrame;
@property (nonatomic, readonly) NSNumber *durationFrames;
@end

View File

@@ -10,18 +10,15 @@
@implementation LAAnimatableNumberValue
- (instancetype)initWithNumberValues:(NSDictionary *)numberValues
keyPath:(NSString *)keyPath
frameRate:(NSNumber *)frameRate {
- (instancetype)initWithNumberValues:(NSDictionary *)numberValues {
self = [super init];
if (self) {
_keyPath = [keyPath copy];
id value = numberValues[@"k"];
if ([value isKindOfClass:[NSArray class]] &&
[[(NSArray *)value firstObject] isKindOfClass:[NSDictionary class]] &&
[(NSDictionary *)[(NSArray *)value firstObject] objectForKey:@"t"]) {
//Keframes
[self _buildAnimationForKeyframes:value keyPath:keyPath frameRate:frameRate];
[self _buildAnimationForKeyframes:value];
} else {
//Single Value, no animation
_initialValue = [[self _numberValueFromObject:value] copy];
@@ -30,23 +27,21 @@
return self;
}
- (void)_buildAnimationForKeyframes:(NSArray<NSDictionary *> *)keyframes
keyPath:(NSString *)keyPath
frameRate:(NSNumber *)frameRate {
- (void)_buildAnimationForKeyframes:(NSArray<NSDictionary *> *)keyframes {
NSMutableArray *keyTimes = [NSMutableArray array];
NSMutableArray *timingFunctions = [NSMutableArray array];
NSMutableArray<NSNumber *> *numberValues = [NSMutableArray array];
NSNumber *startFrame = keyframes.firstObject[@"t"];
_startFrame = keyframes.firstObject[@"t"];
NSNumber *endFrame = keyframes.lastObject[@"t"];
NSAssert((startFrame && endFrame && startFrame.integerValue < endFrame.integerValue),
NSAssert((_startFrame && endFrame && _startFrame.integerValue < endFrame.integerValue),
@"Lotte: Keyframe animation has incorrect time values or invalid number of keyframes");
// Calculate time bounds in second-time.
NSTimeInterval beginTime = startFrame.floatValue / frameRate.floatValue;
NSNumber *durationFrames = @(endFrame.floatValue - startFrame.floatValue);
NSTimeInterval durationTime = durationFrames.floatValue / frameRate.floatValue;
// Calculate time duration
_durationFrames = @(endFrame.floatValue - _startFrame.floatValue);
BOOL addStartValue = YES;
BOOL addTimePadding = NO;
@@ -57,7 +52,7 @@
NSNumber *frame = keyframe[@"t"];
// Calculate percentage value for keyframe.
//CA Animations accept time values of 0-1 as a percentage of animation completed.
NSNumber *timePercentage = @((frame.floatValue - startFrame.floatValue) / durationFrames.floatValue);
NSNumber *timePercentage = @((frame.floatValue - _startFrame.floatValue) / _durationFrames.floatValue);
if (outValue) {
//add out value
@@ -123,14 +118,9 @@
addTimePadding = YES;
}
}
_animation = [CAKeyframeAnimation animationWithKeyPath:keyPath];
_animation.values = numberValues;
_animation.keyTimes = keyTimes;
_animation.timingFunctions = timingFunctions;
_animation.beginTime = beginTime;
_animation.duration = durationTime;
_animation.fillMode = kCAFillModeForwards;
_valueKeyframes = numberValues;
_keyTimes = keyTimes;
_timingFunctions = timingFunctions;
}
- (NSNumber *)_numberValueFromObject:(id)valueObject {

View File

@@ -6,17 +6,17 @@
// Copyright © 2016 Brandon Withrow. All rights reserved.
//
#import "LAAnimatableValue.h"
#import <Foundation/Foundation.h>
@interface LAAnimatablePointValue : NSObject
- (instancetype)initWithPointValues:(NSDictionary *)pointValues
keyPath:(NSString *)keyPath
frameRate:(NSNumber *)frameRate;
- (instancetype)initWithPointValues:(NSDictionary *)pointValues;
@property (nonatomic, readonly) CGPoint initialPoint;
@property (nonatomic, readonly) NSString *keyPath;
@property (nonatomic, readonly) CAKeyframeAnimation *animation;
@property (nonatomic, readonly) UIBezierPath *animationPath;
@property (nonatomic, readonly) NSArray<NSNumber *> *keyTimes;
@property (nonatomic, readonly) NSArray<CAMediaTimingFunction *> *timingFunctions;
@property (nonatomic, readonly) NSNumber *startFrame;
@property (nonatomic, readonly) NSNumber *durationFrames;
@end

View File

@@ -9,21 +9,16 @@
#import "LAAnimatablePointValue.h"
@implementation LAAnimatablePointValue
@synthesize animation = _animation;
@synthesize keyPath = _keyPath;
- (instancetype)initWithPointValues:(NSDictionary *)pointValues
keyPath:(NSString *)keyPath
frameRate:(NSNumber *)frameRate {
- (instancetype)initWithPointValues:(NSDictionary *)pointValues {
self = [super init];
if (self) {
_keyPath = [keyPath copy];
NSArray *value = pointValues[@"k"];
if ([value isKindOfClass:[NSArray class]] &&
[[(NSArray *)value firstObject] isKindOfClass:[NSDictionary class]] &&
[(NSDictionary *)[(NSArray *)value firstObject] objectForKey:@"t"]) {
//Keframes
[self _buildAnimationForKeyframes:value keyPath:keyPath frameRate:frameRate];
[self _buildAnimationForKeyframes:value];
} else {
//Single Value, no animation
_initialPoint = [self _pointFromValueArray:value];
@@ -32,23 +27,19 @@
return self;
}
- (void)_buildAnimationForKeyframes:(NSArray<NSDictionary *> *)keyframes
keyPath:(NSString *)keyPath
frameRate:(NSNumber *)frameRate {
- (void)_buildAnimationForKeyframes:(NSArray<NSDictionary *> *)keyframes {
NSMutableArray *keyTimes = [NSMutableArray array];
NSMutableArray *timingFunctions = [NSMutableArray array];
UIBezierPath *motionPath = [UIBezierPath new];
NSNumber *startFrame = keyframes.firstObject[@"t"];
_startFrame = keyframes.firstObject[@"t"];
NSNumber *endFrame = keyframes.lastObject[@"t"];
NSAssert((startFrame && endFrame && startFrame.integerValue < endFrame.integerValue),
NSAssert((_startFrame && endFrame && _startFrame.integerValue < endFrame.integerValue),
@"Lotte: Keyframe animation has incorrect time values or invalid number of keyframes");
// Calculate time bounds
NSTimeInterval beginTime = startFrame.floatValue / frameRate.floatValue;
NSNumber *durationFrames = @(endFrame.floatValue - startFrame.floatValue);
NSTimeInterval durationTime = durationFrames.floatValue / frameRate.floatValue;
// Calculate time duration
_durationFrames = @(endFrame.floatValue - _startFrame.floatValue);
BOOL addStartValue = YES;
BOOL addTimePadding = NO;
@@ -59,7 +50,7 @@
NSNumber *frame = keyframe[@"t"];
// Calculate percentage value for keyframe.
//CA Animations accept time values of 0-1 as a percentage of animation completed.
NSNumber *timePercentage = @((frame.floatValue - startFrame.floatValue) / durationFrames.floatValue);
NSNumber *timePercentage = @((frame.floatValue - _startFrame.floatValue) / _durationFrames.floatValue);
if (outPoint) {
//add out value
@@ -138,13 +129,9 @@
}
}
_animation = [CAKeyframeAnimation animationWithKeyPath:keyPath];
_animation.path = motionPath.CGPath;
_animation.keyTimes = keyTimes;
_animation.timingFunctions = timingFunctions;
_animation.beginTime = beginTime;
_animation.duration = durationTime;
_animation.fillMode = kCAFillModeForwards;
_animationPath = motionPath;
_keyTimes = keyTimes;
_timingFunctions = timingFunctions;
}
- (CGPoint)_pointFromValueArray:(NSArray<NSNumber *> *)values {

View File

@@ -0,0 +1,23 @@
//
// LAAnimatableSizeValue.h
// LotteAnimator
//
// Created by brandon_withrow on 7/11/16.
// Copyright © 2016 Brandon Withrow. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface LAAnimatableRectValue : NSObject
- (instancetype)initWithRectValues:(NSDictionary *)rectValues;
@property (nonatomic, readonly) CGRect initialRect;
@property (nonatomic, readonly) NSArray *rectKeyframes;
@property (nonatomic, readonly) NSArray<NSNumber *> *keyTimes;
@property (nonatomic, readonly) NSArray<CAMediaTimingFunction *> *timingFunctions;
@property (nonatomic, readonly) NSNumber *startFrame;
@property (nonatomic, readonly) NSNumber *durationFrames;
@end

View File

@@ -0,0 +1,21 @@
//
// 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 {
self = [super init];
if (self) {
}
return self;
}
@end

View File

@@ -0,0 +1,15 @@
//
// LAAnimatableScaleValue.h
// LotteAnimator
//
// Created by brandon_withrow on 7/11/16.
// Copyright © 2016 Brandon Withrow. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface LAAnimatableScaleValue : NSObject
- (instancetype)initWithScaleValues:(NSDictionary *)scaleValues;
@end

View File

@@ -0,0 +1,21 @@
//
// LAAnimatableScaleValue.m
// LotteAnimator
//
// Created by brandon_withrow on 7/11/16.
// Copyright © 2016 Brandon Withrow. All rights reserved.
//
#import "LAAnimatableScaleValue.h"
@implementation LAAnimatableScaleValue
- (instancetype)initWithScaleValues:(NSDictionary *)scaleValues {
self = [super init];
if (self) {
}
return self;
}
@end

View File

@@ -6,18 +6,18 @@
// Copyright © 2016 Brandon Withrow. All rights reserved.
//
#import "LAAnimatableValue.h"
#import <Foundation/Foundation.h>
@interface LAAnimatableShapeValue : NSObject
- (instancetype)initWithShapeValues:(NSDictionary *)shapeValues
keyPath:(NSString *)keyPath
frameRate:(NSNumber *)frameRate
closedPath:(BOOL)closedPath;
- (instancetype)initWithShapeValues:(NSDictionary *)shapeValues closed:(BOOL)closed;
@property (nonatomic, readonly) UIBezierPath *initialShape;
@property (nonatomic, readonly) NSString *keyPath;
@property (nonatomic, readonly) CAKeyframeAnimation *animation;
@property (nonatomic, readonly) NSArray<UIBezierPath *> *shapeKeyframes;
@property (nonatomic, readonly) NSArray<NSNumber *> *keyTimes;
@property (nonatomic, readonly) NSArray<CAMediaTimingFunction *> *timingFunctions;
@property (nonatomic, readonly) NSNumber *startFrame;
@property (nonatomic, readonly) NSNumber *durationFrames;
@end

View File

@@ -9,76 +9,65 @@
#import "LAAnimatableShapeValue.h"
@implementation LAAnimatableShapeValue
@synthesize animation = _animation;
@synthesize keyPath = _keyPath;
- (instancetype)initWithShapeValues:(NSDictionary *)shapeValues
keyPath:(NSString *)keyPath
frameRate:(NSNumber *)frameRate
closedPath:(BOOL)closedPath {
- (instancetype)initWithShapeValues:(NSDictionary *)shapeValues closed:(BOOL)closed {
self = [super init];
if (self) {
_keyPath = [keyPath copy];
id value = shapeValues[@"k"];
if ([value isKindOfClass:[NSArray class]] &&
[[(NSArray *)value firstObject] isKindOfClass:[NSDictionary class]] &&
[(NSDictionary *)[(NSArray *)value firstObject] objectForKey:@"t"]) {
//Keframes
[self _buildAnimationForKeyframes:value keyPath:keyPath frameRate:frameRate closedPath:closedPath];
} else {
[self _buildAnimationForKeyframes:value closed:closed];
} else if ([value isKindOfClass:[NSDictionary class]]) {
//Single Value, no animation
_initialShape = [self _bezierShapeFromValue:value closedPath:closedPath];
_initialShape = [self _bezierShapeFromValue:value closed:closed];
}
}
return self;
}
- (void)_buildAnimationForKeyframes:(NSArray<NSDictionary *> *)keyframes
keyPath:(NSString *)keyPath
frameRate:(NSNumber *)frameRate
closedPath:(BOOL)closedPath {
- (void)_buildAnimationForKeyframes:(NSArray<NSDictionary *> *)keyframes closed:(BOOL)closed {
NSMutableArray *keyTimes = [NSMutableArray array];
NSMutableArray *timingFunctions = [NSMutableArray array];
NSMutableArray *shapeValues = [NSMutableArray array];
NSMutableArray<UIBezierPath *> *shapeValues = [NSMutableArray array];
NSNumber *startFrame = keyframes.firstObject[@"t"];
_startFrame = keyframes.firstObject[@"t"];
NSNumber *endFrame = keyframes.lastObject[@"t"];
NSAssert((startFrame && endFrame && startFrame.integerValue < endFrame.integerValue),
NSAssert((_startFrame && endFrame && _startFrame.integerValue < endFrame.integerValue),
@"Lotte: Keyframe animation has incorrect time values or invalid number of keyframes");
// Calculate time bounds
NSTimeInterval beginTime = startFrame.floatValue / frameRate.floatValue;
NSNumber *durationFrames = @(endFrame.floatValue - startFrame.floatValue);
NSTimeInterval durationTime = durationFrames.floatValue / frameRate.floatValue;
// Calculate time duration
_durationFrames = @(endFrame.floatValue - _startFrame.floatValue);
BOOL addStartValue = YES;
BOOL addTimePadding = NO;
UIBezierPath *outShape = nil;
NSDictionary *outShape = nil;
for (NSDictionary *keyframe in keyframes) {
// Get keyframe time value
NSNumber *frame = keyframe[@"t"];
// Calculate percentage value for keyframe.
//CA Animations accept time values of 0-1 as a percentage of animation completed.
NSNumber *timePercentage = @((frame.floatValue - startFrame.floatValue) / durationFrames.floatValue);
NSNumber *timePercentage = @((frame.floatValue - _startFrame.floatValue) / _durationFrames.floatValue);
if (outShape) {
//add out value
[shapeValues addObject:(id)[[outShape copy] CGPath]];
[shapeValues addObject:[self _bezierShapeFromValue:outShape closed:closed]];
[timingFunctions addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
outShape = nil;
}
UIBezierPath *startShape = [self _bezierShapeFromValue:keyframe[@"s"] closedPath:closedPath];
NSDictionary *startShape = keyframe[@"s"];
if (addStartValue) {
// Add start value
if (startShape) {
if (keyframe == keyframes.firstObject) {
_initialShape = startShape;
_initialShape = [self _bezierShapeFromValue:startShape closed:closed];
}
[shapeValues addObject:(id)[[startShape copy] CGPath]];
[shapeValues addObject:[self _bezierShapeFromValue:startShape closed:closed]];
if (timingFunctions.count) {
[timingFunctions addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
}
@@ -94,9 +83,9 @@
}
// add end value if present for keyframe
UIBezierPath *endShape = [self _bezierShapeFromValue:keyframe[@"e"] closedPath:closedPath];
NSDictionary *endShape = keyframe[@"e"];
if (endShape) {
[shapeValues addObject:(id)[[endShape copy] CGColor]];
[shapeValues addObject:[self _bezierShapeFromValue:endShape closed:closed]];
/*
* Timing Function for time interpolations between keyframes
* Should be n-1 where n is the number of keyframes
@@ -128,17 +117,13 @@
addTimePadding = YES;
}
}
_animation = [CAKeyframeAnimation animationWithKeyPath:keyPath];
_animation.values = shapeValues;
_animation.keyTimes = keyTimes;
_animation.timingFunctions = timingFunctions;
_animation.beginTime = beginTime;
_animation.duration = durationTime;
_animation.fillMode = kCAFillModeForwards;
_shapeKeyframes = shapeValues;
_keyTimes = keyTimes;
_timingFunctions = timingFunctions;
}
- (UIBezierPath *)_bezierShapeFromValue:(id)value closedPath:(BOOL)closedPath {
- (UIBezierPath *)_bezierShapeFromValue:(id)value closed:(BOOL)closedPath {
NSDictionary *pointsData = nil;
if ([value isKindOfClass:[NSArray class]] &&
[[(NSArray *)value firstObject] isKindOfClass:[NSDictionary class]] &&

View File

@@ -1,16 +0,0 @@
//
// LAAnimatableProperty.h
// LotteAnimator
//
// Created by brandon_withrow on 6/22/16.
// Copyright © 2016 Brandon Withrow. All rights reserved.
//
#import <Foundation/Foundation.h>
@protocol LAAnimatableValue <NSObject>
@property (nonatomic, readonly) NSString *keyPath;
@property (nonatomic, readonly) CAKeyframeAnimation *animation;
@end

View File

@@ -10,9 +10,9 @@
@interface LACompView : UIView
- (instancetype)initWithModel:(LAScene *)model;
- (instancetype)initWithModel:(LAComposition *)model;
@property (nonatomic, strong) LAScene *sceneModel;
@property (nonatomic, strong) LAComposition *sceneModel;
@property (nonatomic, assign) BOOL debugModeOn;
@end

View File

@@ -10,8 +10,8 @@
@implementation LACompView
- (instancetype)initWithModel:(LAScene *)model {
self = [super initWithFrame:CGRectMake(0, 0, model.compWidth.floatValue, model.compHeight.floatValue)];
- (instancetype)initWithModel:(LAComposition *)model {
self = [super initWithFrame:model.compBounds];
if (self) {
_sceneModel = model;
for (LALayer *layer in model.layers) {

View File

@@ -6,16 +6,18 @@
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "MTLModel.h"
#import <Foundation/Foundation.h>
@class LALayer;
@interface LAComposition : MTLModel <MTLJSONSerializing>
@interface LAComposition : NSObject
@property (nonatomic, strong) NSArray <LALayer *> *layers;
@property (nonatomic, strong) NSNumber *compWidth;
@property (nonatomic, strong) NSNumber *compHeight;
@property (nonatomic, strong) NSNumber *startFrame;
@property (nonatomic, strong) NSNumber *endFrame;
@property (nonatomic, strong) NSNumber *framerate;
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary;
@property (nonatomic, readonly) NSArray <LALayer *> *layers;
@property (nonatomic, readonly) CGRect compBounds;
@property (nonatomic, readonly) NSNumber *startFrame;
@property (nonatomic, readonly) NSNumber *endFrame;
@property (nonatomic, readonly) NSNumber *framerate;
@property (nonatomic, readonly) NSTimeInterval timeDuration;
@end

View File

@@ -11,18 +11,39 @@
@implementation LAComposition
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"compWidth" : @"w",
@"compHeight" : @"h",
@"framerate" : @"fr",
@"startFrame" : @"ip",
@"endFrame" : @"op",
@"layers" : @"layers"};
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary {
self = [super init];
if (self) {
[self _mapFromJSON:jsonDictionary];
}
return self;
}
+ (NSValueTransformer *)layersJSONTransformer {
// tell Mantle to populate diaAttributes property with an array of MDAttribute objects
return [MTLJSONAdapter arrayTransformerWithModelClass:[LALayer class]];
- (void)_mapFromJSON:(NSDictionary *)jsonDictionary {
NSNumber *width = jsonDictionary[@"w"];
NSNumber *height = jsonDictionary[@"h"];
if (width && height) {
CGRect bounds = CGRectMake(0, 0, width.floatValue, height.floatValue);
_compBounds = bounds;
}
_startFrame = [jsonDictionary[@"ip"] copy];
_endFrame = [jsonDictionary[@"op"] copy];
_framerate = [jsonDictionary[@"fr"] copy];
if (_startFrame && _endFrame && _framerate) {
NSInteger frameDuration = _endFrame.integerValue - _startFrame.integerValue;
NSTimeInterval timeDuration = frameDuration / _framerate.floatValue;
_timeDuration = timeDuration;
}
NSArray *layersJSON = jsonDictionary[@"layers"];
NSMutableArray *layers = [NSMutableArray array];
for (NSDictionary *layerJSON in layersJSON) {
LALayer *layer = [[LALayer alloc] initWithJSON:layerJSON frameRate:_framerate];
[layers addObject:layer];
}
_layers = layers;
}
@end

View File

@@ -6,17 +6,18 @@
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "MTLModel.h"
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class LALayerView;
@class LAShape;
@class LAShapeGroup;
@class LAMask;
@class LAAnimatableColorValue;
@class LAAnimatablePointValue;
@class LAAnimatableNumberValue;
@class LAAnimatableRectValue;
@class LAAnimatableScaleValue;
typedef enum : NSUInteger {
typedef enum : NSInteger {
LALayerTypeNone,
LALayerTypeSolid,
LALayerTypeUnknown,
@@ -24,25 +25,27 @@ typedef enum : NSUInteger {
LALayerTypeShape
} LALayerType;
@interface LALayer : MTLModel <MTLJSONSerializing>
@interface LALayer : NSObject
@property (nonatomic, copy) NSString *layerName;
@property (nonatomic, copy) NSNumber *layerID;
@property (nonatomic, assign) LALayerType layerType;
@property (nonatomic, copy) NSNumber *parentID;
@property (nonatomic, copy) NSNumber *inPoint;
@property (nonatomic, copy) NSNumber *outPoint;
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate;
@property (nonatomic, copy) NSArray<LAShape *> *shapes;
@property (nonatomic, copy) NSArray<LAMask *> *masks;
@property (nonatomic, copy) LAAnimatableNumberValue *solidWidth;
@property (nonatomic, copy) LAAnimatableNumberValue *solidHeight;
@property (nonatomic, copy) LAAnimatableColorValue *solidColor;
@property (nonatomic, readonly) NSString *layerName;
@property (nonatomic, readonly) NSNumber *layerID;
@property (nonatomic, readonly) LALayerType layerType;
@property (nonatomic, readonly) NSNumber *parentID;
@property (nonatomic, readonly) NSNumber *inFrame;
@property (nonatomic, readonly) NSNumber *outFrame;
@property (nonatomic, copy) LAAnimatableNumberValue *opacity;
@property (nonatomic, copy) LAAnimatableNumberValue *rotation;
@property (nonatomic, copy) LAAnimatablePointValue *position;
@property (nonatomic, copy) LAAnimatablePointValue *anchor;
//@property (nonatomic, copy) LAAnimatableProperty *scale; //TODO Make This
@property (nonatomic, readonly) NSArray<LAShapeGroup *> *shapes;
@property (nonatomic, readonly) NSArray<LAMask *> *masks;
@property (nonatomic, readonly) LAAnimatableRectValue *solidBounds;
@property (nonatomic, readonly) LAAnimatableColorValue *solidColor;
@property (nonatomic, readonly) LAAnimatableNumberValue *opacity;
@property (nonatomic, readonly) LAAnimatableNumberValue *rotation;
@property (nonatomic, readonly) LAAnimatablePointValue *position;
@property (nonatomic, readonly) LAAnimatablePointValue *anchor;
@property (nonatomic, readonly) LAAnimatableScaleValue *scale;
@end

View File

@@ -10,143 +10,77 @@
#import "LAAnimatableColorValue.h"
#import "LAAnimatablePointValue.h"
#import "LAAnimatableNumberValue.h"
#import "LAAnimatableScaleValue.h"
#import "LAShapeGroup.h"
@implementation LALayer
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
// model_property_name : json_field_name
return @{
@"layerName" : @"layerName",
@"layerID" : @"ind",
@"layerType" : @"ty",
@"parentID" : @"parent",
@"inPoint" : @"ip",
@"outPoint" : @"op",
@"rotation" : @"ks.r",
@"position" : @"ks.p",
@"anchor" : @"ks.a",
// @"scale" : @"ks.s",
@"opacity" : @"ks.o",
@"solidWidth" : @"sw",
@"solidHeight" : @"sh",
@"solidColor" : @"sc",
// @"masks" : @"masksProperties",
// @"shapes" : @"shapes"
};
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
self = [super init];
if (self) {
[self _mapFromJSON:jsonDictionary frameRate:frameRate];
}
return self;
}
+ (NSValueTransformer *)shapesJSONTransformer {
return [MTLJSONAdapter arrayTransformerWithModelClass:[LAShape class]];
- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
_layerName = [jsonDictionary[@"nm"] copy];
_layerID = [jsonDictionary[@"ind"] copy];
NSNumber *layerType = jsonDictionary[@"ty"];
if (layerType.integerValue <= LALayerTypeShape) {
_layerType = layerType.integerValue;
} else {
_layerType = LALayerTypeUnknown;
}
_parentID = [jsonDictionary[@"parent"] copy];
_inFrame = [jsonDictionary[@"ip"] copy];
_outFrame = [jsonDictionary[@"op"] copy];
if (_layerType == LALayerTypeSolid) {
// TODO Solids.
}
NSDictionary *opacity = jsonDictionary[@"ks.o"];
if (opacity) {
_opacity = [[LAAnimatableNumberValue alloc] initWithNumberValues:opacity];
}
NSDictionary *rotation = jsonDictionary[@"ks.r"];
if (rotation) {
_rotation = [[LAAnimatableNumberValue alloc] initWithNumberValues:rotation];
}
NSDictionary *position = jsonDictionary[@"ks.p"];
if (position) {
_position = [[LAAnimatablePointValue alloc] initWithPointValues:position];
}
NSDictionary *anchor = jsonDictionary[@"ks.a"];
if (anchor) {
_anchor = [[LAAnimatablePointValue alloc] initWithPointValues:anchor];
}
NSDictionary *scale = jsonDictionary[@"ks.s"];
if (scale) {
_scale = [[LAAnimatableScaleValue alloc] initWithScaleValues:scale];
}
NSMutableArray *masks = [NSMutableArray array];
for (NSDictionary *maskJSON in jsonDictionary[@"masksProperties"]) {
LAMask *mask = [[LAMask alloc] initWithJSON:maskJSON frameRate:frameRate];
[masks addObject:mask];
}
_masks = masks;
NSMutableArray *shapes = [NSMutableArray array];
for (NSDictionary *shapeJSON in jsonDictionary[@"shapes"]) {
LAShapeGroup *group = [[LAShapeGroup alloc] initWithJSON:shapeJSON frameRate:frameRate];
[shapes addObject:group];
}
_shapes = shapes;
}
+ (NSValueTransformer *)masksJSONTransformer {
return [MTLJSONAdapter arrayTransformerWithModelClass:[LAMask class]];
}
+ (NSValueTransformer *)rotationJSONTransformer {
return [MTLValueTransformer transformerUsingForwardBlock:^id(NSDictionary *value, BOOL *success, NSError *__autoreleasing *error) {
if (value == nil) {
return nil;
}
if (![value isKindOfClass:NSDictionary.class]) {
if (error != NULL) {
NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: NSLocalizedString(@"Could not convert JSON dictionary to model object", @""),
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:NSLocalizedString(@"Expected an NSDictionary, got: %@", @""), value],
MTLTransformerErrorHandlingInputValueErrorKey : value
};
*error = [NSError errorWithDomain:MTLTransformerErrorHandlingErrorDomain code:MTLTransformerErrorHandlingErrorInvalidInput userInfo:userInfo];
}
*success = NO;
return nil;
}
LAAnimatableNumberValue *numvalue = [[LAAnimatableNumberValue alloc] initWithNumberValues:<#(NSDictionary *)#> keyPath:<#(NSString *)#> frameRate:<#(NSNumber *)#>]
}];
}
//+ (NSValueTransformer *)rotationJSONTransformer {
// return [LAAnimatableValue animatablePropertyValueTransformerForKey:@"rotation"];
//}
//
//+ (NSValueTransformer *)positionJSONTransformer {
// return [LAAnimatableValue animatablePropertyValueTransformerForKey:@"position"];
//}
//
//+ (NSValueTransformer *)anchorJSONTransformer {
// return [LAAnimatableValue animatablePropertyValueTransformerForKey:@"anchor"];
//}
//
//+ (NSValueTransformer *)scaleJSONTransformer {
// return [LAAnimatableValue animatablePropertyValueTransformerForKey:@"scale"];
//}
//
//+ (NSValueTransformer *)opacityJSONTransformer {
// return [LAAnimatableValue animatablePropertyValueTransformerForKey:@"opacity"];
//}
//- (UIColor *)bgColor {
// if (!self.color) {
// return [UIColor clearColor];
// }
// NSString *hexString = [self.color copy];
// hexString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
//
// return [UIColor colorWithHexString:hexString];
//}
//
//- (CGPoint)position {
// if (!self.positionArray) {
// return CGPointZero;
// }
// CGPoint aePosition = CGPointMake([self.positionArray[0] floatValue], [self.positionArray[1] floatValue]);
// if (self.anchorPointArray) {
// aePosition.x -= [self.anchorPointArray[0] floatValue];
// aePosition.y -= [self.anchorPointArray[1] floatValue];
// }
// return aePosition;
//}
//
//- (CGPoint)anchorPoint {
// if (!self.anchorPointArray) {
// return CGPointZero;
// }
// CGPoint aeAnchorPoint = CGPointMake([self.anchorPointArray[0] floatValue], [self.anchorPointArray[1] floatValue]);
// CGPoint uikitAnchorPoint = CGPointMake(aeAnchorPoint.x / self.size.width,
// aeAnchorPoint.y / self.size.height);
// return uikitAnchorPoint;
//}
//
//- (CGSize)size {
// if (!self.width && !self.height) {
// return CGSizeZero;
// }
// return CGSizeMake(self.width.floatValue, self.height.floatValue);
//}
//
//- (CGSize)scale {
// if (!self.scaleArray) {
// return CGSizeZero;
// }
// return CGSizeMake([self.scaleArray[0] floatValue] / 100.f, [self.scaleArray[1] floatValue] / 100.f);
//}
//
//- (CGFloat)alpha {
// if (!self.opacity) {
// return 1;
// }
// return self.opacity.floatValue / 100.f;
//}
//
//- (CGRect)frameRect {
// return CGRectMake(self.position.x, self.position.y, self.size.width, self.size.height);
//}
//
//- (CGAffineTransform)transform {
// return CGAffineTransformRotate(CGAffineTransformMakeScale(self.scale.width, self.scale.height), DegreesToRadians(self.rotation ? self.rotation.floatValue : 0.f));
//}
@end

View File

@@ -6,13 +6,25 @@
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "MTLModel.h"
#import <Foundation/Foundation.h>
@class LAAnimatableShapeValue;
@class LAAnimatableNumberValue;
@interface LAMask : MTLModel <MTLJSONSerializing>
typedef enum : NSUInteger {
LAMaskModeAdd,
LAMaskModeSubtract,
LAMaskModeIntersect,
LAMaskModeUnknown
} LAMaskMode;
@property (nonatomic, getter=isClosed) BOOL closed;
@property (nonatomic, getter=isInverted) BOOL inverted;
@property (nonatomic, strong) LAPath *maskPath;
@property (nonatomic, copy) NSNumber *opacity;
@interface LAMask : NSObject
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate;
@property (nonatomic, readonly) BOOL closed;
@property (nonatomic, readonly) BOOL inverted;
@property (nonatomic, readonly) LAMaskMode maskMode;
@property (nonatomic, readonly) LAAnimatableShapeValue *maskPath;
@property (nonatomic, readonly) LAAnimatableNumberValue *opacity;
@end

View File

@@ -7,27 +7,46 @@
//
#import "LAMask.h"
#import "LAAnimatableShapeValue.h"
#import "LAAnimatableNumberValue.h"
@implementation LAMask
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"closed" : @"cl",
@"inverted" : @"inv",
@"maskPath" : @"pt",
@"opacity" : @"o"};
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
self = [super init];
if (self) {
[self _mapFromJSON:jsonDictionary frameRate:frameRate];
}
return self;
}
+ (NSValueTransformer *)maskPathJSONTransformer {
// tell Mantle to populate diaAttributes property with an array of MDAttribute objects
return [MTLJSONAdapter dictionaryTransformerWithModelClass:[LAPath class]];
}
+ (NSValueTransformer *)closedJSONTransformer {
return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName];
}
+ (NSValueTransformer *)invertedJSONTransformer {
return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName];
- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
NSNumber *closed = jsonDictionary[@"cl"];
_closed = closed.boolValue;
NSNumber *inverted = jsonDictionary[@"inv"];
_inverted = inverted.boolValue;
NSString *mode = jsonDictionary[@"mode"];
if ([mode isEqualToString:@"a"]) {
_maskMode = LAMaskModeAdd;
} else if ([mode isEqualToString:@"s"]) {
_maskMode = LAMaskModeSubtract;
} else if ([mode isEqualToString:@"i"]) {
_maskMode = LAMaskModeIntersect;
} else {
_maskMode = LAMaskModeUnknown;
}
NSDictionary *maskshape = jsonDictionary[@"pt"];
if (maskshape) {
_maskPath = [[LAAnimatableShapeValue alloc] initWithShapeValues:maskshape closed:_closed];
}
NSDictionary *opacity = jsonDictionary[@"o"];
if (opacity) {
_opacity = [[LAAnimatableNumberValue alloc] initWithNumberValues:opacity];
}
}
@end

View File

@@ -9,12 +9,10 @@
#ifndef LAModels_h
#define LAModels_h
#import "LAPath.h"
#import "LAMask.h"
#import "LAComposition.h"
#import "LALayer.h"
#import "LAShape.h"
#import "LAShapeItem.h"
#import "LAShapeGroup.h"
#import "LAShapePath.h"
#import "LAShapeStroke.h"
#import "LAShapeFill.h"

View File

@@ -1,19 +0,0 @@
//
// LABezierPath.h
// LotteAnimator
//
// Created by Brandon Withrow on 12/14/15.
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "MTLModel.h"
@interface LAPath : MTLModel <MTLJSONSerializing>
@property (nonatomic, strong) NSArray *points;
@property (nonatomic, strong) NSArray *inTangents;
@property (nonatomic, strong) NSArray *outTangents;
- (UIBezierPath *)bezierPath:(BOOL)closedPath;
@end

View File

@@ -1,54 +0,0 @@
//
// LABezierPath.m
// LotteAnimator
//
// Created by Brandon Withrow on 12/14/15.
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "LAPath.h"
@implementation LAPath
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"points" : @"v",
@"inTangents" : @"i",
@"outTangents" : @"o"};
}
- (UIBezierPath *)bezierPath:(BOOL)closedPath {
if (!self.points.count) {
return nil;
}
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:[self _vertexAtIndex:0]];
for (int i = 1; i < self.points.count; i ++) {
[path addCurveToPoint:[self _vertexAtIndex:i] controlPoint1:[self _outTangentAtIndex:i - 1] controlPoint2:[self _inTangentAtIndex:i]];
}
if (closedPath) {
[path addCurveToPoint:[self _vertexAtIndex:0] controlPoint1:[self _outTangentAtIndex:self.points.count - 1] controlPoint2:[self _inTangentAtIndex:0]];
[path closePath];
}
return path;
}
- (CGPoint)_vertexAtIndex:(NSInteger)idx {
NSArray *pointArray = self.points[idx];
return CGPointMake([pointArray[0] floatValue], [pointArray[1] floatValue]);
}
- (CGPoint)_outTangentAtIndex:(NSInteger)idx {
NSArray *outArray = self.outTangents[idx];
CGPoint vertex = [self _vertexAtIndex:idx];
return CGPointMake([outArray[0] floatValue] + vertex.x, [outArray[1] floatValue] + vertex.y);
}
- (CGPoint)_inTangentAtIndex:(NSInteger)idx {
NSArray *inArray = self.inTangents[idx];
CGPoint vertex = [self _vertexAtIndex:idx];
return CGPointMake([inArray[0] floatValue] + vertex.x, [inArray[1] floatValue] + vertex.y);
}
@end

View File

@@ -1,21 +0,0 @@
//
// LAShape.h
// LotteAnimator
//
// Created by Brandon Withrow on 12/14/15.
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "MTLModel.h"
@interface LAShape : MTLModel <MTLJSONSerializing>
@property (nonatomic, copy) NSArray *shapeItems;
// TODO Map these items more efficiently for use in LALayerView
// This is extremely inefficient and unsafe.
@property (nonatomic, readonly) NSArray *paths;
@property (nonatomic, readonly) NSArray *strokes;
@property (nonatomic, readonly) NSArray *fills;
@property (nonatomic, readonly) NSArray *transforms;
@end

View File

@@ -1,85 +0,0 @@
//
// LAShape.m
// LotteAnimator
//
// Created by Brandon Withrow on 12/14/15.
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "LAShape.h"
#import "LAShapeItem.h"
@implementation LAShape
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"shapeItems" : @"it"};
}
+ (NSValueTransformer *)shapeItemsJSONTransformer {
// tell Mantle to populate diaAttributes property with an array of MDAttribute objects
return [MTLJSONAdapter arrayTransformerWithModelClass:[LAShapeItem class]];
}
- (NSArray *)paths {
if (!self.shapeItems) {
return @[];
}
NSMutableArray *paths = [NSMutableArray array];
for (LAShapeItem *item in self.shapeItems) {
if ([item.itemType isEqualToString:LAShapeItemType.Path] ||
[item.itemType isEqualToString:LAShapeItemType.Circle] ||
[item.itemType isEqualToString:LAShapeItemType.Rectangle]) {
[paths addObject:item];
}
}
return paths;
}
- (NSArray *)strokes {
if (!self.shapeItems) {
return @[];
}
NSMutableArray *strokes = [NSMutableArray array];
for (LAShapeItem *item in self.shapeItems) {
if ([item.itemType isEqualToString:LAShapeItemType.Stroke]) {
[strokes addObject:item];
}
}
return strokes;
}
- (NSArray *)fills {
if (!self.shapeItems) {
return @[];
}
NSMutableArray *fills = [NSMutableArray array];
for (LAShapeItem *item in self.shapeItems) {
if ([item.itemType isEqualToString:LAShapeItemType.Fill]) {
[fills addObject:item];
}
}
return fills;
}
- (NSArray *)transforms {
if (!self.shapeItems) {
return @[];
}
NSMutableArray *transforms = [NSMutableArray array];
for (LAShapeItem *item in self.shapeItems) {
if ([item.itemType isEqualToString:LAShapeItemType.Transform]) {
[transforms addObject:item];
}
}
return transforms;
}
@end

View File

@@ -6,14 +6,10 @@
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "LAShapeItem.h"
#import <Foundation/Foundation.h>
@interface LAShapeCircle : LAShapeItem
@interface LAShapeCircle : NSObject
@property (nonatomic, copy) NSArray *positionArray;
@property (nonatomic, copy) NSArray *sizeArray;
@property (nonatomic, readonly) CGPoint position;
@property (nonatomic, readonly) CGSize size;
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate;
@end

View File

@@ -10,30 +10,16 @@
@implementation LAShapeCircle
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"itemType" : @"ty",
@"positionArray" : @"p",
@"sizeArray" : @"s"};
}
- (CGPoint)position {
if (!self.positionArray) {
return CGPointZero;
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
self = [super init];
if (self) {
[self _mapFromJSON:jsonDictionary frameRate:frameRate];
}
CGPoint aePosition = CGPointMake([self.positionArray[0] floatValue], [self.positionArray[1] floatValue]);
return aePosition;
return self;
}
- (CGSize)size {
if (!self.sizeArray) {
return CGSizeZero;
}
return CGSizeMake([self.sizeArray[0] floatValue], [self.sizeArray[1] floatValue]);
- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
}
- (UIBezierPath *)path {
CGRect circleBounds = CGRectMake(self.size.width * -0.5, self.size.height * -0.5, self.size.width, self.size.height);
return [UIBezierPath bezierPathWithOvalInRect:circleBounds];
}
@end

View File

@@ -6,14 +6,17 @@
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "LAShapeItem.h"
#import <Foundation/Foundation.h>
@interface LAShapeFill : LAShapeItem
@class LAAnimatableColorValue;
@class LAAnimatableNumberValue;
@property (nonatomic, getter=isFillEnabled) BOOL fillEnabled;
@property (nonatomic, copy) NSArray *colorElements;
@property (nonatomic, copy) NSNumber *opacity;
@interface LAShapeFill : NSObject
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate;
@property (nonatomic, readonly) BOOL fillEnabled;
@property (nonatomic, readonly) LAAnimatableColorValue *color;
@property (nonatomic, readonly) LAAnimatableNumberValue *opacity;
@property (nonatomic, readonly) UIColor *color;
@property (nonatomic, readonly) CGFloat alpha;
@end

View File

@@ -7,35 +7,32 @@
//
#import "LAShapeFill.h"
#import "LAAnimatableNumberValue.h"
#import "LAAnimatableColorValue.h"
@implementation LAShapeFill
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"itemType" : @"ty",
@"fillEnabled" : @"fillEnabled",
@"colorElements" : @"c",
@"opacity" : @"o"};
}
+ (NSValueTransformer *)fillEnabledJSONTransformer {
return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName];
}
- (CGFloat)alpha {
if (!self.opacity) {
return 1;
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
self = [super init];
if (self) {
[self _mapFromJSON:jsonDictionary frameRate:frameRate];
}
return self.opacity.floatValue / 100.f;
return self;
}
- (UIColor *)color {
if (!self.colorElements) {
return [UIColor clearColor];
- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
NSDictionary *color = jsonDictionary[@"c"];
if (color) {
_color = [[LAAnimatableColorValue alloc] initWithColorValues:color];
}
return [UIColor colorWithRed:([self.colorElements[0] floatValue]/255.f)
green:([self.colorElements[1] floatValue]/255.f)
blue:([self.colorElements[2] floatValue]/255.f)
alpha:([self.colorElements[3] floatValue]/255.f)];
NSDictionary *opacity = jsonDictionary[@"o"];
if (opacity) {
_opacity = [[LAAnimatableNumberValue alloc] initWithNumberValues:opacity];
}
NSNumber *fillEnabled = jsonDictionary[@"fillEnabled"];
_fillEnabled = fillEnabled.boolValue;
}
@end

View File

@@ -0,0 +1,17 @@
//
// LAShape.h
// LotteAnimator
//
// Created by Brandon Withrow on 12/14/15.
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface LAShapeGroup : NSObject
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate;
@property (nonatomic, readonly) NSArray *items;
@end

View File

@@ -0,0 +1,59 @@
//
// LAShape.m
// LotteAnimator
//
// Created by Brandon Withrow on 12/14/15.
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "LAShapeGroup.h"
#import "LAShapeFill.h"
#import "LAShapePath.h"
#import "LAShapeCircle.h"
#import "LAShapeStroke.h"
#import "LAShapeTransform.h"
#import "LAShapeRectangle.h"
@implementation LAShapeGroup
- (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 {
NSArray *itemsJSON = jsonDictionary[@"it"];
NSMutableArray *items = [NSMutableArray array];
for (NSDictionary *itemJSON in itemsJSON) {
NSString *type = itemJSON[@"ty"];
if ([type isEqualToString:@"gr"]) {
LAShapeGroup *group = [[LAShapeGroup alloc] initWithJSON:itemJSON frameRate:frameRate];
[items addObject:group];
} else if ([type isEqualToString:@"st"]) {
LAShapeStroke *stroke = [[LAShapeStroke alloc] initWithJSON:itemJSON frameRate:frameRate];
[items addObject:stroke];
} else if ([type isEqualToString:@"fl"]) {
LAShapeFill *fill = [[LAShapeFill alloc] initWithJSON:itemJSON frameRate:frameRate];
[items addObject:fill];
} else if ([type isEqualToString:@"tr"]) {
LAShapeTransform *transform = [[LAShapeTransform alloc] initWithJSON:itemJSON frameRate:frameRate];
[items addObject:transform];
} else if ([type isEqualToString:@"sh"]) {
LAShapePath *path = [[LAShapePath alloc] initWithJSON:itemJSON frameRate:frameRate];
[items addObject:path];
} else if ([type isEqualToString:@"el"]) {
LAShapeCircle *circle = [[LAShapeCircle alloc] initWithJSON:itemJSON frameRate:frameRate];
[items addObject:circle];
} else if ([type isEqualToString:@"rc"]) {
LAShapeRectangle *rectangle = [[LAShapeRectangle alloc] initWithJSON:itemJSON frameRate:frameRate];
[items addObject:rectangle];
}
}
_items = items;
}
@end

View File

@@ -1,28 +0,0 @@
//
// LAShapeItem.h
// LotteAnimator
//
// Created by Brandon Withrow on 12/15/15.
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "MTLModel.h"
struct LAShapeItemType {
__unsafe_unretained NSString * const Path;
__unsafe_unretained NSString * const Stroke;
__unsafe_unretained NSString * const Fill;
__unsafe_unretained NSString * const Transform;
__unsafe_unretained NSString * const Circle;
__unsafe_unretained NSString * const Rectangle;
};
extern const struct LAShapeItemType LAShapeItemType;
@interface LAShapeItem : MTLModel <MTLJSONSerializing>
@property (nonatomic, copy) NSString *itemType;
@property (nonatomic, readonly) UIBezierPath *path;
@end

View File

@@ -1,54 +0,0 @@
//
// LAShapeItem.m
// LotteAnimator
//
// Created by Brandon Withrow on 12/15/15.
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "LAShapeItem.h"
const struct LAShapeItemType LAShapeItemType = {
.Path = @"sh",
.Stroke = @"st",
.Fill = @"fl",
.Transform = @"tr",
.Circle = @"el",
.Rectangle = @"rc"
};
@implementation LAShapeItem
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"itemType" : @"ty"};
}
+ (Class)classForParsingJSONDictionary:(NSDictionary *)JSONDictionary {
if ([JSONDictionary[@"ty"] isEqual:LAShapeItemType.Path]) {
return LAShapePath.class;
}
if ([JSONDictionary[@"ty"] isEqual:LAShapeItemType.Stroke]) {
return LAShapeStroke.class;
}
if ([JSONDictionary[@"ty"] isEqual:LAShapeItemType.Fill]) {
return LAShapeFill.class;
}
if ([JSONDictionary[@"ty"] isEqual:LAShapeItemType.Transform]) {
return LAShapeTransform.class;
}
if ([JSONDictionary[@"ty"] isEqual:LAShapeItemType.Circle]) {
return LAShapeCircle.class;
}
if ([JSONDictionary[@"ty"] isEqual:LAShapeItemType.Rectangle]) {
return LAShapeRectangle.class;
}
return self;
}
@end

View File

@@ -6,11 +6,16 @@
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "LAShapeItem.h"
#import <Foundation/Foundation.h>
@interface LAShapePath : LAShapeItem
@class LAAnimatableShapeValue;
@property (nonatomic, getter=isClosed) BOOL closed;
@property (nonatomic, strong) LAPath *shapePath;
@interface LAShapePath : NSObject
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate;
@property (nonatomic, readonly) BOOL closed;
@property (nonatomic, readonly) NSNumber *index;
@property (nonatomic, readonly) LAAnimatableShapeValue *shapePath;
@end

View File

@@ -7,25 +7,25 @@
//
#import "LAShapePath.h"
#import "LAAnimatableShapeValue.h"
@implementation LAShapePath
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"itemType" : @"ty",
@"closed" : @"closed",
@"shapePath" : @"ks"};
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
self = [super init];
if (self) {
[self _mapFromJSON:jsonDictionary frameRate:frameRate];
}
return self;
}
+ (NSValueTransformer *)shapePathJSONTransformer {
// tell Mantle to populate diaAttributes property with an array of MDAttribute objects
return [MTLJSONAdapter dictionaryTransformerWithModelClass:[LAPath class]];
- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
_index = jsonDictionary[@"ind"];
_closed = [jsonDictionary[@"closed"] boolValue];
NSDictionary *shape = jsonDictionary[@"ks"];
if (shape) {
_shapePath = [[LAAnimatableShapeValue alloc] initWithShapeValues:shape closed:_closed];
}
}
+ (NSValueTransformer *)closedJSONTransformer {
return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName];
}
- (UIBezierPath *)path {
return [self.shapePath bezierPath:self.isClosed];
}
@end

View File

@@ -6,15 +6,10 @@
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "LAShapeItem.h"
#import <Foundation/Foundation.h>
@interface LAShapeRectangle : LAShapeItem
@interface LAShapeRectangle : NSObject
@property (nonatomic, copy) NSArray *positionArray;
@property (nonatomic, copy) NSArray *sizeArray;
@property (nonatomic, copy) NSNumber *cornerRadius;
@property (nonatomic, readonly) CGPoint position;
@property (nonatomic, readonly) CGSize size;
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate;
@end

View File

@@ -10,38 +10,16 @@
@implementation LAShapeRectangle
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"itemType" : @"ty",
@"positionArray" : @"p",
@"sizeArray" : @"s",
@"cornerRadius" : @"r"};
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
self = [super init];
if (self) {
[self _mapFromJSON:jsonDictionary frameRate:frameRate];
}
return self;
}
- (CGPoint)position {
if (!self.positionArray) {
return CGPointZero;
}
CGPoint aePosition = CGPointMake([self.positionArray[0] floatValue], [self.positionArray[1] floatValue]);
- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
return aePosition;
}
- (CGSize)size {
if (!self.sizeArray) {
return CGSizeZero;
}
return CGSizeMake([self.sizeArray[0] floatValue], [self.sizeArray[1] floatValue]);
}
- (UIBezierPath *)path {
CGRect rectBounds = CGRectMake(self.size.width * -0.5, self.size.height * -0.5, self.size.width, self.size.height);
UIBezierPath *path;
if (self.cornerRadius && self.cornerRadius.floatValue > 0.0) {
path = [UIBezierPath bezierPathWithRoundedRect:rectBounds cornerRadius:self.cornerRadius.floatValue];
} else {
path = [UIBezierPath bezierPathWithRect:rectBounds];
}
return path;
}
@end

View File

@@ -6,16 +6,18 @@
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "LAShapeItem.h"
#import <Foundation/Foundation.h>
@interface LAShapeStroke : LAShapeItem
@class LAAnimatableColorValue;
@class LAAnimatableNumberValue;
@property (nonatomic, getter=isFillEnabled) BOOL fillEnabled;
@property (nonatomic, copy) NSArray *colorElements;
@property (nonatomic, copy) NSNumber *opacity;
@property (nonatomic, copy) NSNumber *width;
@interface LAShapeStroke : NSObject
@property (nonatomic, readonly) UIColor *color;
@property (nonatomic, readonly) CGFloat alpha;
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate;
@property (nonatomic, readonly) BOOL fillEnabled;
@property (nonatomic, readonly) LAAnimatableColorValue *color;
@property (nonatomic, readonly) LAAnimatableNumberValue *opacity;
@property (nonatomic, readonly) LAAnimatableNumberValue *width;
@end

View File

@@ -7,36 +7,37 @@
//
#import "LAShapeStroke.h"
#import "LAAnimatableNumberValue.h"
#import "LAAnimatableColorValue.h"
@implementation LAShapeStroke
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"itemType" : @"ty",
@"fillEnabled" : @"fillEnabled",
@"colorElements" : @"c",
@"opacity" : @"o",
@"width" : @"w"};
}
+ (NSValueTransformer *)fillEnabledJSONTransformer {
return [NSValueTransformer valueTransformerForName:MTLBooleanValueTransformerName];
}
- (CGFloat)alpha {
if (!self.opacity) {
return 1;
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
self = [super init];
if (self) {
[self _mapFromJSON:jsonDictionary frameRate:frameRate];
}
return self.opacity.floatValue / 100.f;
return self;
}
- (UIColor *)color {
if (!self.colorElements) {
return [UIColor clearColor];
- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
NSDictionary *color = jsonDictionary[@"c"];
if (color) {
_color = [[LAAnimatableColorValue alloc] initWithColorValues:color];
}
return [UIColor colorWithRed:([self.colorElements[0] floatValue]/255.f)
green:([self.colorElements[1] floatValue]/255.f)
blue:([self.colorElements[2] floatValue]/255.f)
alpha:([self.colorElements[3] floatValue]/255.f)];
NSDictionary *width = jsonDictionary[@"w"];
if (width) {
_width = [[LAAnimatableNumberValue alloc] initWithNumberValues:width];
}
NSDictionary *opacity = jsonDictionary[@"o"];
if (opacity) {
_opacity = [[LAAnimatableNumberValue alloc] initWithNumberValues:opacity];
}
NSNumber *fillEnabled = jsonDictionary[@"fillEnabled"];
_fillEnabled = fillEnabled.boolValue;
}
@end

View File

@@ -6,20 +6,20 @@
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "LAShapeItem.h"
#import <Foundation/Foundation.h>
@interface LAShapeTransform : LAShapeItem
@class LAAnimatableNumberValue;
@class LAAnimatablePointValue;
@class LAAnimatableScaleValue;
@property (nonatomic, copy) NSArray *positionArray;
@property (nonatomic, copy) NSArray *anchorPointArray;
@property (nonatomic, copy) NSArray *scaleArray;
@property (nonatomic, copy) NSNumber *rotation;
@property (nonatomic, copy) NSNumber *opacity;
@interface LAShapeTransform : NSObject
@property (nonatomic, readonly) CGPoint position;
@property (nonatomic, readonly) CGPoint anchorPoint;
@property (nonatomic, readonly) CGSize scale;
@property (nonatomic, readonly) CGFloat alpha;
@property (nonatomic, readonly) CGAffineTransform transform;
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate;
@property (nonatomic, readonly) LAAnimatablePointValue *position;
@property (nonatomic, readonly) LAAnimatablePointValue *anchor;
@property (nonatomic, readonly) LAAnimatableScaleValue *scale;
@property (nonatomic, readonly) LAAnimatableNumberValue *rotation;
@property (nonatomic, readonly) LAAnimatableNumberValue *opacity;
@end

View File

@@ -7,61 +7,45 @@
//
#import "LAShapeTransform.h"
#import "LAAnimatableNumberValue.h"
#import "LAAnimatablePointValue.h"
#import "LAAnimatableScaleValue.h"
@implementation LAShapeTransform
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return @{@"itemType" : @"ty",
@"positionArray" : @"p",
@"anchorPointArray" : @"a",
@"scaleArray" : @"s",
@"rotation" : @"r",
@"opacity" : @"o"};
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
self = [super init];
if (self) {
[self _mapFromJSON:jsonDictionary frameRate:frameRate];
}
return self;
}
- (CGPoint)position {
if (!self.positionArray) {
return CGPointZero;
- (void)_mapFromJSON:(NSDictionary *)jsonDictionary frameRate:(NSNumber *)frameRate {
NSDictionary *position = jsonDictionary[@"p"];
if (position) {
_position = [[LAAnimatablePointValue alloc] initWithPointValues:position];
}
CGPoint aePosition = CGPointMake([self.positionArray[0] floatValue], [self.positionArray[1] floatValue]);
if (self.anchorPointArray) {
aePosition.x -= [self.anchorPointArray[0] floatValue];
aePosition.y -= [self.anchorPointArray[1] floatValue];
NSDictionary *anchor = jsonDictionary[@"a"];
if (anchor) {
_anchor = [[LAAnimatablePointValue alloc] initWithPointValues:anchor];
}
return aePosition;
}
- (CGPoint)anchorPoint {
if (!self.anchorPointArray) {
return CGPointZero;
NSDictionary *scale = jsonDictionary[@"s"];
if (scale) {
_scale = [[LAAnimatableScaleValue alloc] initWithScaleValues:scale];
}
CGPoint aeAnchorPoint = CGPointMake([self.anchorPointArray[0] floatValue], [self.anchorPointArray[1] floatValue]);
// CGPoint uikitAnchorPoint = CGPointMake(aeAnchorPoint.x / self.size.width,
// aeAnchorPoint.y / self.size.height);
// TODO Figure out this crazy thing
return aeAnchorPoint;
}
// TODO Permanently Unwrap these arrays for efficency
- (CGSize)scale {
if (!self.scaleArray) {
return CGSizeZero;
NSDictionary *rotation = jsonDictionary[@"r"];
if (rotation) {
_rotation = [[LAAnimatableNumberValue alloc] initWithNumberValues:rotation];
}
return CGSizeMake([self.scaleArray[0] floatValue] / 100.f, [self.scaleArray[1] floatValue] / 100.f);
}
- (CGFloat)alpha {
if (!self.opacity) {
return 1;
NSDictionary *opacity = jsonDictionary[@"o"];
if (opacity) {
_opacity = [[LAAnimatableNumberValue alloc] initWithNumberValues:opacity];
}
return self.opacity.floatValue / 100.f;
}
- (CGAffineTransform)transform {
CGAffineTransform translate = CGAffineTransformMakeTranslation(self.position.x, self.position.y);
CGAffineTransform scale = CGAffineTransformScale(translate, self.scale.width, self.scale.height);
CGAffineTransform rotate = CGAffineTransformRotate(scale, DegreesToRadians(self.rotation ? self.rotation.floatValue : 0.f));
return rotate;
}
@end

View File

@@ -33,7 +33,7 @@
NSData *jsonData = [[NSData alloc] initWithContentsOfFile:filePath];
NSDictionary *JSONObject = [NSJSONSerialization JSONObjectWithData:jsonData
options:0 error:&error];
LAComposition *laScene = [MTLJSONAdapter modelOfClass:[LAComposition class] fromJSONDictionary:JSONObject error:&error];
LAComposition *laScene = [[LAComposition alloc] initWithJSON:JSONObject];
}