Enable time remapping

This commit is contained in:
brandon_withrow 2018-01-03 14:50:47 -08:00
parent 650a82eb2d
commit 6434ec156f
27 changed files with 1102 additions and 1015 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
{"v":"4.12.0","fr":23.9759979248047,"ip":0,"op":48.9999957589018,"w":300,"h":300,"nm":"TimeRemap","ddd":0,"assets":[{"id":"comp_1","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"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":[360]},{"t":47.9999958454548}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[150,60,0],"e":[150,225,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[150,225,0],"e":[150,60,0],"to":[0,0,0],"ti":[0,0,0]},{"t":47.9999958454548}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[109.172,109.172],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.431255026425,0,0.902665022308,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.32,4.668],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":48.9999957589018,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Freeze","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[146,220,0],"ix":2},"a":{"a":0,"k":[150,150,0],"ix":1},"s":{"a":0,"k":[50.667,50.667,100],"ix":6}},"ao":0,"tm":{"a":0,"k":0.876,"ix":2},"w":300,"h":300,"ip":0,"op":48.9999957589018,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Reverse","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[247,220,0],"ix":2},"a":{"a":0,"k":[150,150,0],"ix":1},"s":{"a":0,"k":[50.667,50.667,100],"ix":6}},"ao":0,"tm":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[2.044],"e":[0]},{"t":48.9999957589018}],"ix":2},"w":300,"h":300,"ip":0,"op":48.9999957589018,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"Regular","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[43,220,0],"ix":2},"a":{"a":0,"k":[150,150,0],"ix":1},"s":{"a":0,"k":[50.667,50.667,100],"ix":6}},"ao":0,"w":300,"h":300,"ip":0,"op":48.9999957589018,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"Stretch","refId":"comp_1","sr":0.2,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[44,71,0],"ix":2},"a":{"a":0,"k":[150,150,0],"ix":1},"s":{"a":0,"k":[50.667,50.667,100],"ix":6}},"ao":0,"w":300,"h":300,"ip":0,"op":9.79999915178036,"st":0,"bm":0}]}

View File

@ -64,6 +64,7 @@
622F77091F2BE63100269858 /* X.json in Resources */ = {isa = PBXBuildFile; fileRef = 622F76EB1F2BE63100269858 /* X.json */; };
622F770A1F2BE63100269858 /* Y.json in Resources */ = {isa = PBXBuildFile; fileRef = 622F76EC1F2BE63100269858 /* Y.json */; };
622F770B1F2BE63100269858 /* Z.json in Resources */ = {isa = PBXBuildFile; fileRef = 622F76ED1F2BE63100269858 /* Z.json */; };
6257F31E1FFD65BC00DAE7B2 /* timeremap.json in Resources */ = {isa = PBXBuildFile; fileRef = 6257F31D1FFD65BB00DAE7B2 /* timeremap.json */; };
6289F3851FE4A3F500C10B3E /* setValueTest.json in Resources */ = {isa = PBXBuildFile; fileRef = 6289F3841FE4A3F500C10B3E /* setValueTest.json */; };
6289F3871FE877FC00C10B3E /* GeometryTransformTest.json in Resources */ = {isa = PBXBuildFile; fileRef = 6289F3861FE877FC00C10B3E /* GeometryTransformTest.json */; };
6289F3881FE877FC00C10B3E /* GeometryTransformTest.json in Resources */ = {isa = PBXBuildFile; fileRef = 6289F3861FE877FC00C10B3E /* GeometryTransformTest.json */; };
@ -176,6 +177,7 @@
622F76EC1F2BE63100269858 /* Y.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Y.json; sourceTree = "<group>"; };
622F76ED1F2BE63100269858 /* Z.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Z.json; sourceTree = "<group>"; };
62569CB2461B12ABC97FCB96 /* lottie-ios.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = "lottie-ios.podspec"; path = "../lottie-ios.podspec"; sourceTree = "<group>"; };
6257F31D1FFD65BB00DAE7B2 /* timeremap.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = timeremap.json; sourceTree = "<group>"; };
6289F3841FE4A3F500C10B3E /* setValueTest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = setValueTest.json; sourceTree = "<group>"; };
6289F3861FE877FC00C10B3E /* GeometryTransformTest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = GeometryTransformTest.json; sourceTree = "<group>"; };
6289F3891FE8784200C10B3E /* LAGeometryTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LAGeometryTest.m; sourceTree = "<group>"; };
@ -373,6 +375,7 @@
622F76B91F2BE58100269858 /* LottieLogo1.json */,
622F76BB1F2BE58100269858 /* MotionCorpse-Jrcanest.json */,
622F76BC1F2BE58100269858 /* PinJump.json */,
6257F31D1FFD65BB00DAE7B2 /* timeremap.json */,
622F76BD1F2BE58100269858 /* TwitterHeart.json */,
622F76BF1F2BE58100269858 /* vcTransition1.json */,
622F76C01F2BE58100269858 /* vcTransition2.json */,
@ -628,6 +631,7 @@
622F77021F2BE63100269858 /* Q.json in Resources */,
629EC5811F54C00B005B2C59 /* Switch.json in Resources */,
622F76FB1F2BE63100269858 /* J.json in Resources */,
6257F31E1FFD65BC00DAE7B2 /* timeremap.json in Resources */,
622F77081F2BE63100269858 /* W.json in Resources */,
622F76F61F2BE63100269858 /* E.json in Resources */,
622F76C41F2BE58100269858 /* IconTransitions.json in Resources */,

View File

@ -939,7 +939,7 @@
62CA59AF1E3C173B002D7188 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0830;
LastUpgradeCheck = 0910;
ORGANIZATIONNAME = Airbnb;
TargetAttributes = {
62CA59B71E3C173B002D7188 = {
@ -1187,7 +1187,9 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
@ -1195,7 +1197,11 @@
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@ -1240,7 +1246,9 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
@ -1248,7 +1256,11 @@
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0830"
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -36,6 +37,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0830"
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -36,6 +37,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

BIN
_AeFiles/TimeRemap.aep Normal file

Binary file not shown.

View File

@ -14,11 +14,13 @@
#import "LOTAnimatorNode.h"
#import "LOTRenderNode.h"
#import "LOTRenderGroup.h"
#import "LOTNumberInterpolator.h"
@implementation LOTCompositionContainer {
NSNumber *_frameOffset;
CALayer *DEBUG_Center;
NSMutableDictionary *_keypathCache;
LOTNumberInterpolator *_timeInterpolator;
}
- (instancetype)initWithModel:(LOTLayer *)layer
@ -41,6 +43,11 @@
} else {
_frameOffset = @0;
}
if (layer.timeRemapping) {
_timeInterpolator = [[LOTNumberInterpolator alloc] initWithKeyframes:layer.timeRemapping.keyframes];
}
[self initializeWithChildGroup:childLayerGroup withAssetGroup:assetGroup];
}
return self;
@ -89,9 +96,12 @@
- (void)displayWithFrame:(NSNumber *)frame forceUpdate:(BOOL)forceUpdate {
if (ENABLE_DEBUG_LOGGING) NSLog(@"-------------------- Composition Displaying Frame %@ --------------------", frame);
[super displayWithFrame:frame forceUpdate:forceUpdate];
NSNumber *childFrame = @(frame.floatValue - _frameOffset.floatValue);
NSNumber *newFrame = @((frame.floatValue - _frameOffset.floatValue) / self.timeStretchFactor.floatValue);
if (_timeInterpolator) {
newFrame = @([_timeInterpolator floatValueForFrame:newFrame]);
}
for (LOTLayerContainer *child in _childLayers) {
[child displayWithFrame:childFrame forceUpdate:forceUpdate];
[child displayWithFrame:newFrame forceUpdate:forceUpdate];
}
if (ENABLE_DEBUG_LOGGING) NSLog(@"-------------------- ------------------------------- --------------------");
if (ENABLE_DEBUG_LOGGING) NSLog(@"-------------------- ------------------------------- --------------------");

View File

@ -10,7 +10,8 @@
#import "LOTLayer.h"
#import "LOTLayerGroup.h"
#import "LOTKeypath.h"
#import "LOTValueCallback.h"
@class LOTValueCallback;
@interface LOTLayerContainer : CALayer
@ -19,9 +20,11 @@
@property (nonatomic, readonly, strong, nullable) NSString *layerName;
@property (nonatomic, nullable) NSNumber *currentFrame;
@property (nonatomic, readonly, nonnull) NSNumber *timeStretchFactor;
@property (nonatomic, assign) CGRect viewportBounds;
@property (nonatomic, readonly, nonnull) CALayer *wrapperLayer;
@property (nonatomic, readonly, nonnull) NSDictionary *valueInterpolators;
- (void)displayWithFrame:(NSNumber * _Nonnull)frame;
- (void)displayWithFrame:(NSNumber * _Nonnull)frame forceUpdate:(BOOL)forceUpdate;

View File

@ -49,6 +49,7 @@
}
self.actions = @{@"hidden" : [NSNull null], @"opacity" : [NSNull null], @"transform" : [NSNull null]};
_wrapperLayer.actions = [self.actions copy];
_timeStretchFactor = @1;
[self commonInitializeWith:layer inLayerGroup:layerGroup];
}
return self;
@ -75,7 +76,10 @@
_inFrame = [layer.inFrame copy];
_outFrame = [layer.outFrame copy];
_timeStretchFactor = [layer.timeStretch copy];
_transformInterpolator = [LOTTransformInterpolator transformForLayer:layer];
if (layer.parentID) {
NSNumber *parentID = layer.parentID;
LOTTransformInterpolator *childInterpolator = _transformInterpolator;
@ -233,7 +237,8 @@
}
- (void)displayWithFrame:(NSNumber *)frame forceUpdate:(BOOL)forceUpdate {
if (ENABLE_DEBUG_LOGGING) NSLog(@"View %@ Displaying Frame %@", self, frame);
NSNumber *newFrame = @(frame.floatValue / self.timeStretchFactor.floatValue);
if (ENABLE_DEBUG_LOGGING) NSLog(@"View %@ Displaying Frame %@, with local time %@", self, frame, newFrame);
BOOL hidden = NO;
if (_inFrame && _outFrame) {
hidden = (frame.floatValue < _inFrame.floatValue ||
@ -243,14 +248,14 @@
if (hidden) {
return;
}
if (_opacityInterpolator && [_opacityInterpolator hasUpdateForFrame:frame]) {
self.opacity = [_opacityInterpolator floatValueForFrame:frame];
if (_opacityInterpolator && [_opacityInterpolator hasUpdateForFrame:newFrame]) {
self.opacity = [_opacityInterpolator floatValueForFrame:newFrame];
}
if (_transformInterpolator && [_transformInterpolator hasUpdateForFrame:frame]) {
_wrapperLayer.transform = [_transformInterpolator transformForFrame:frame];
if (_transformInterpolator && [_transformInterpolator hasUpdateForFrame:newFrame]) {
_wrapperLayer.transform = [_transformInterpolator transformForFrame:newFrame];
}
[_contentsGroup updateWithFrame:frame withModifierBlock:nil forceLocalUpdate:forceUpdate];
_maskLayer.currentFrame = frame;
[_contentsGroup updateWithFrame:newFrame withModifierBlock:nil forceLocalUpdate:forceUpdate];
_maskLayer.currentFrame = newFrame;
}
- (void)setViewportBounds:(CGRect)viewportBounds {

View File

@ -19,7 +19,8 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary
withAssetGroup:(LOTAssetGroup * _Nullable)assetGroup
withAssetBundle:(NSBundle *_Nonnull)bundle;
withAssetBundle:(NSBundle *_Nonnull)bundle
withFramerate:(NSNumber *)framerate;
@property (nonatomic, readonly, nullable) NSString *referenceID;
@property (nonatomic, readonly, nullable) NSNumber *assetWidth;

View File

@ -15,18 +15,21 @@
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary
withAssetGroup:(LOTAssetGroup * _Nullable)assetGroup
withAssetBundle:(NSBundle *_Nonnull)bundle {
withAssetBundle:(NSBundle *_Nonnull)bundle
withFramerate:(NSNumber *)framerate {
self = [super init];
if (self) {
_assetBundle = bundle;
[self _mapFromJSON:jsonDictionary
withAssetGroup:assetGroup];
withAssetGroup:assetGroup
withFramerate:framerate];
}
return self;
}
- (void)_mapFromJSON:(NSDictionary *)jsonDictionary
withAssetGroup:(LOTAssetGroup * _Nullable)assetGroup {
withAssetGroup:(LOTAssetGroup * _Nullable)assetGroup
withFramerate:(NSNumber *)framerate {
_referenceID = [jsonDictionary[@"id"] copy];
if (jsonDictionary[@"w"]) {
@ -48,7 +51,8 @@
NSArray *layersJSON = jsonDictionary[@"layers"];
if (layersJSON) {
_layerGroup = [[LOTLayerGroup alloc] initWithLayerJSON:layersJSON
withAssetGroup:assetGroup];
withAssetGroup:assetGroup
withFramerate:framerate];
}
}

View File

@ -16,11 +16,12 @@
@property (nonatomic, readonly, nullable) NSBundle *assetBundle;
- (instancetype _Nonnull)initWithJSON:(NSArray * _Nonnull)jsonArray
withAssetBundle:(NSBundle *_Nullable)bundle;
withAssetBundle:(NSBundle *_Nullable)bundle
withFramerate:(NSNumber * _Nonnull)framerate;
- (void)buildAssetNamed:(NSString * _Nonnull)refID;
- (void)buildAssetNamed:(NSString * _Nonnull)refID withFramerate:(NSNumber * _Nonnull)framerate;
- (void)finalizeInitialization;
- (void)finalizeInitializationWithFramerate:(NSNumber * _Nonnull)framerate;
- (LOTAsset * _Nullable)assetModelForID:(NSString * _Nonnull)assetID;

View File

@ -15,7 +15,8 @@
}
- (instancetype _Nonnull)initWithJSON:(NSArray * _Nonnull)jsonArray
withAssetBundle:(NSBundle *_Nullable)bundle {
withAssetBundle:(NSBundle * _Nullable)bundle
withFramerate:(NSNumber * _Nonnull)framerate {
self = [super init];
if (self) {
_assetBundle = bundle;
@ -32,7 +33,8 @@
return self;
}
- (void)buildAssetNamed:(NSString *)refID {
- (void)buildAssetNamed:(NSString *)refID
withFramerate:(NSNumber * _Nonnull)framerate {
if ([self assetModelForID:refID]) {
return;
@ -42,14 +44,15 @@
if (assetDictionary) {
LOTAsset *asset = [[LOTAsset alloc] initWithJSON:assetDictionary
withAssetGroup:self
withAssetBundle:_assetBundle];
withAssetBundle:_assetBundle
withFramerate:framerate];
_assetMap[refID] = asset;
}
}
- (void)finalizeInitialization {
- (void)finalizeInitializationWithFramerate:(NSNumber * _Nonnull)framerate {
for (NSString *refID in _assetJSONMap.allKeys) {
[self buildAssetNamed:refID];
[self buildAssetNamed:refID withFramerate:framerate];
}
_assetJSONMap = nil;
}

View File

@ -36,7 +36,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface LOTLayer : NSObject
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary
withAssetGroup:(LOTAssetGroup * _Nullable)assetGroup;
withAssetGroup:(LOTAssetGroup * _Nullable)assetGroup
withFramerate:(NSNumber *)framerate;
@property (nonatomic, readonly) NSString *layerName;
@property (nonatomic, readonly, nullable) NSString *referenceID;
@ -46,6 +47,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) NSNumber *startFrame;
@property (nonatomic, readonly) NSNumber *inFrame;
@property (nonatomic, readonly) NSNumber *outFrame;
@property (nonatomic, readonly) NSNumber *timeStretch;
@property (nonatomic, readonly) CGRect layerBounds;
@property (nonatomic, readonly, nullable) NSArray<LOTShapeGroup *> *shapes;
@ -57,6 +59,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly, nullable) LOTAsset *imageAsset;
@property (nonatomic, readonly) LOTKeyframeGroup *opacity;
@property (nonatomic, readonly, nullable) LOTKeyframeGroup *timeRemapping;
@property (nonatomic, readonly) LOTKeyframeGroup *rotation;
@property (nonatomic, readonly, nullable) LOTKeyframeGroup *position;

View File

@ -18,17 +18,20 @@
@implementation LOTLayer
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary
withAssetGroup:(LOTAssetGroup *)assetGroup {
withAssetGroup:(LOTAssetGroup *)assetGroup
withFramerate:(NSNumber *)framerate {
self = [super init];
if (self) {
[self _mapFromJSON:jsonDictionary
withAssetGroup:assetGroup];
withAssetGroup:assetGroup
withFramerate:framerate];
}
return self;
}
- (void)_mapFromJSON:(NSDictionary *)jsonDictionary
withAssetGroup:(LOTAssetGroup *)assetGroup {
withAssetGroup:(LOTAssetGroup *)assetGroup
withFramerate:(NSNumber *)framerate {
_layerName = [jsonDictionary[@"nm"] copy];
_layerID = [jsonDictionary[@"ind"] copy];
@ -48,12 +51,18 @@
_inFrame = [jsonDictionary[@"ip"] copy];
_outFrame = [jsonDictionary[@"op"] copy];
if (jsonDictionary[@"sr"]) {
_timeStretch = [jsonDictionary[@"sr"] copy];
} else {
_timeStretch = @1;
}
if (_layerType == LOTLayerTypePrecomp) {
_layerHeight = [jsonDictionary[@"h"] copy];
_layerWidth = [jsonDictionary[@"w"] copy];
[assetGroup buildAssetNamed:_referenceID];
[assetGroup buildAssetNamed:_referenceID withFramerate:framerate];
} else if (_layerType == LOTLayerTypeImage) {
[assetGroup buildAssetNamed:_referenceID];
[assetGroup buildAssetNamed:_referenceID withFramerate:framerate];
_imageAsset = [assetGroup assetModelForID:_referenceID];
_layerWidth = [_imageAsset.assetWidth copy];
_layerHeight = [_imageAsset.assetHeight copy];
@ -75,6 +84,14 @@
return LOT_RemapValue(inValue, 0, 100, 0, 1);
}];
}
NSDictionary *timeRemap = jsonDictionary[@"tm"];
if (timeRemap) {
_timeRemapping = [[LOTKeyframeGroup alloc] initWithData:timeRemap];
[_timeRemapping remapKeyframesWithBlock:^CGFloat(CGFloat inValue) {
return inValue * framerate.doubleValue;
}];
}
NSDictionary *rotation = ks[@"r"];
if (rotation == nil) {

View File

@ -17,7 +17,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface LOTLayerGroup : NSObject
- (instancetype)initWithLayerJSON:(NSArray *)layersJSON
withAssetGroup:(LOTAssetGroup * _Nullable)assetGroup;
withAssetGroup:(LOTAssetGroup * _Nullable)assetGroup
withFramerate:(NSNumber *)framerate;
@property (nonatomic, readonly) NSArray <LOTLayer *> *layers;

View File

@ -16,15 +16,18 @@
}
- (instancetype)initWithLayerJSON:(NSArray *)layersJSON
withAssetGroup:(LOTAssetGroup * _Nullable)assetGroup {
withAssetGroup:(LOTAssetGroup * _Nullable)assetGroup
withFramerate:(NSNumber *)framerate {
self = [super init];
if (self) {
[self _mapFromJSON:layersJSON withAssetGroup:assetGroup];
[self _mapFromJSON:layersJSON withAssetGroup:assetGroup withFramerate:framerate];
}
return self;
}
- (void)_mapFromJSON:(NSArray *)layersJSON withAssetGroup:(LOTAssetGroup * _Nullable)assetGroup {
- (void)_mapFromJSON:(NSArray *)layersJSON
withAssetGroup:(LOTAssetGroup * _Nullable)assetGroup
withFramerate:(NSNumber *)framerate {
NSMutableArray *layers = [NSMutableArray array];
NSMutableDictionary *modelMap = [NSMutableDictionary dictionary];
@ -32,7 +35,8 @@
for (NSDictionary *layerJSON in layersJSON) {
LOTLayer *layer = [[LOTLayer alloc] initWithJSON:layerJSON
withAssetGroup:assetGroup];
withAssetGroup:assetGroup
withFramerate:framerate];
[layers addObject:layer];
modelMap[layer.layerID] = layer;
if (layer.referenceID) {

View File

@ -112,16 +112,17 @@
NSArray *assetArray = jsonDictionary[@"assets"];
if (assetArray.count) {
_assetGroup = [[LOTAssetGroup alloc] initWithJSON:assetArray withAssetBundle:bundle];
_assetGroup = [[LOTAssetGroup alloc] initWithJSON:assetArray withAssetBundle:bundle withFramerate:_framerate];
}
NSArray *layersJSON = jsonDictionary[@"layers"];
if (layersJSON) {
_layerGroup = [[LOTLayerGroup alloc] initWithLayerJSON:layersJSON
withAssetGroup:_assetGroup];
withAssetGroup:_assetGroup
withFramerate:_framerate];
}
[_assetGroup finalizeInitialization];
[_assetGroup finalizeInitializationWithFramerate:_framerate];
}
- (void)setRootDirectory:(NSString *)rootDirectory {

View File

@ -7,7 +7,7 @@
//
#import <Foundation/Foundation.h>
#import "LOTPlatformCompat.h"
#import <CoreGraphics/CoreGraphics.h>
/*!
@brief A block that is used to change a Color value at keytime, the block is called continuously for a keypath while the aniamtion plays.
@ -19,14 +19,15 @@
@param interpolatedProgress A value from 0-1 that represents the current progress between keyframes. It respects the keyframes current easing curves.
@param currentFrame The current frame of the animation in the parent compositions time space.
@return UIColor the color to set the keypath node for the current frame
*/
typedef UIColor * _Nonnull (^LOTColorValueCallbackBlock)(CGFloat startFrame,
CGFloat endFrame,
UIColor * _Nullable startColor,
UIColor * _Nullable endColor,
UIColor * _Nullable interpolatedColor,
CGFloat interpolatedProgress,
CGFloat currentFrame);
*/
typedef CGColorRef _Nonnull (^LOTColorValueCallbackBlock)(CGFloat startFrame,
CGFloat endFrame,
CGColorRef _Nullable startColor,
CGColorRef _Nullable endColor,
CGColorRef _Nullable interpolatedColor,
CGFloat interpolatedProgress,
CGFloat currentFrame);
/*!
@brief A block that is used to change a Number value at keytime, the block is called continuously for a keypath while the aniamtion plays.
@param startFrame When the block is called, startFrame is the most recent keyframe for the keypath in relation to the current time.
@ -91,10 +92,11 @@ typedef CGSize (^LOTSizeValueCallbackBlock)(CGFloat startFrame,
@param currentFrame The current frame of the animation in the parent compositions time space.
@return UIBezierPath the path to set the keypath node for the current frame.
*/
typedef UIBezierPath * _Nonnull (^LOTPathValueCallbackBlock)(CGFloat startFrame,
CGFloat endFrame,
CGFloat interpolatedProgress,
CGFloat currentFrame);
typedef CGPathRef _Nonnull (^LOTPathValueCallbackBlock)(CGFloat startFrame,
CGFloat endFrame,
CGFloat interpolatedProgress,
CGFloat currentFrame);
/*!
@brief LOTValueCallback is a thin wrapper around a value block. It is not intended to be used directly. It has several child classes that are each associated with a value type that can be used to change animations at runtime.
@ -163,5 +165,4 @@ typedef UIBezierPath * _Nonnull (^LOTPathValueCallbackBlock)(CGFloat startFrame,
@property (nonatomic, copy, nonnull) LOTPathValueCallbackBlock callback;
@end

View File

@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface LOTColorInterpolator : LOTValueInterpolator
- (UIColor *)colorForFrame:(NSNumber *)frame;
- (CGColorRef)colorForFrame:(NSNumber *)frame;
@property (nonatomic, strong, nullable) LOTColorValueCallback *colorCallback;

View File

@ -12,7 +12,7 @@
@implementation LOTColorInterpolator
- (UIColor *)colorForFrame:(NSNumber *)frame {
- (CGColorRef)colorForFrame:(NSNumber *)frame {
CGFloat progress = [self progressForFrame:frame];
UIColor *returnColor;
@ -24,10 +24,10 @@
returnColor = [UIColor LOT_colorByLerpingFromColor:self.leadingKeyframe.colorValue toColor:self.trailingKeyframe.colorValue amount:progress];
}
if (self.hasValueOverride) {
return self.colorCallback.callback(self.leadingKeyframe.keyframeTime.floatValue, self.trailingKeyframe.keyframeTime.floatValue, self.leadingKeyframe.colorValue, self.trailingKeyframe.colorValue, returnColor, progress, frame.floatValue);
return self.colorCallback.callback(self.leadingKeyframe.keyframeTime.floatValue, self.trailingKeyframe.keyframeTime.floatValue, self.leadingKeyframe.colorValue.CGColor, self.trailingKeyframe.colorValue.CGColor, returnColor.CGColor, progress, frame.floatValue);
}
return returnColor;
return returnColor.CGColor;
}
- (void)setValueCallback:(LOTValueCallback *)valueCallback {

View File

@ -14,8 +14,8 @@
- (LOTBezierPath *)pathForFrame:(NSNumber *)frame cacheLengths:(BOOL)cacheLengths {
CGFloat progress = [self progressForFrame:frame];
if (self.hasValueOverride) {
UIBezierPath *path = self.pathCallback.callback(self.leadingKeyframe.keyframeTime.floatValue, self.trailingKeyframe.keyframeTime.floatValue, progress, frame.floatValue);
return [LOTBezierPath pathWithCGPath:path.CGPath];
CGPathRef callBackPath = self.pathCallback.callback(self.leadingKeyframe.keyframeTime.floatValue, self.trailingKeyframe.keyframeTime.floatValue, progress, frame.floatValue);
return [LOTBezierPath pathWithCGPath:callBackPath];
}
LOTBezierPath *returnPath = [[LOTBezierPath alloc] init];

View File

@ -46,10 +46,10 @@
}
- (void)performLocalUpdate {
centerPoint_DEBUG.backgroundColor = [colorInterpolator_ colorForFrame:self.currentFrame].CGColor;
centerPoint_DEBUG.backgroundColor = [colorInterpolator_ colorForFrame:self.currentFrame];
centerPoint_DEBUG.borderColor = [UIColor lightGrayColor].CGColor;
centerPoint_DEBUG.borderWidth = 2.f;
self.outputLayer.fillColor = [colorInterpolator_ colorForFrame:self.currentFrame].CGColor;
self.outputLayer.fillColor = [colorInterpolator_ colorForFrame:self.currentFrame];
self.outputLayer.opacity = [opacityInterpolator_ floatValueForFrame:self.currentFrame];
}

View File

@ -104,7 +104,7 @@
- (void)performLocalUpdate {
self.outputLayer.lineDashPhase = [_dashOffsetInterpolator floatValueForFrame:self.currentFrame];
self.outputLayer.strokeColor = [_colorInterpolator colorForFrame:self.currentFrame].CGColor;
self.outputLayer.strokeColor = [_colorInterpolator colorForFrame:self.currentFrame];
self.outputLayer.lineWidth = [_widthInterpolator floatValueForFrame:self.currentFrame];
self.outputLayer.opacity = [_opacityInterpolator floatValueForFrame:self.currentFrame];
}