Initial work on interactive props

This commit is contained in:
brandon_withrow
2017-12-18 15:10:28 -08:00
parent e42812f94f
commit a2275e9227
41 changed files with 2316 additions and 1131 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,9 @@
#import "LOTAnimationView.h"
#import "LOTAnimationView_Compat.h"
#import "LOTComposition.h"
#import "LOTKeypath.h"
#import "Lottie.h"
#import "LOTValueCallback.h"
FOUNDATION_EXPORT double LottieVersionNumber;
FOUNDATION_EXPORT const unsigned char LottieVersionString[];

View File

@@ -10,7 +10,9 @@
#import "LOTAnimationView_Compat.h"
#import "LOTCacheProvider.h"
#import "LOTComposition.h"
#import "LOTKeypath.h"
#import "Lottie.h"
#import "LOTValueCallback.h"
FOUNDATION_EXPORT double LottieVersionNumber;
FOUNDATION_EXPORT const unsigned char LottieVersionString[];

View File

@@ -0,0 +1 @@
{"v":"4.12.0","fr":23.9759979248047,"ip":0,"op":48.9999957589018,"w":300,"h":300,"nm":"Comp 2","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Scaled","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"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":[{"d":1,"ty":"el","s":{"a":0,"k":[68.52,68.52],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","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,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[200,200],"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":48.9999957589018,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"TopLeft","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"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":[{"d":1,"ty":"el","s":{"a":0,"k":[68.52,68.52],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","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":[-150,-150],"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":48.9999957589018,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"BottomRight","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"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":[{"d":1,"ty":"el","s":{"a":0,"k":[68.52,68.52],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","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":[150,150],"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":48.9999957589018,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Center","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"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":[{"d":1,"ty":"el","s":{"a":0,"k":[68.52,68.52],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","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,0],"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":48.9999957589018,"st":0,"bm":0}]}

View File

@@ -0,0 +1,62 @@
//
// LAGeometryTest.m
// lottie-ios_Tests
//
// Created by brandon_withrow on 12/18/17.
// Copyright © 2017 Brandon Withrow. All rights reserved.
//
#import <XCTest/XCTest.h>
#import <Lottie/Lottie.h>
@interface LAGeometryTest : XCTestCase
@property (nonatomic, strong) LOTAnimationView *animationView;
@end
@implementation LAGeometryTest
- (void)setUp {
[super setUp];
self.animationView = [LOTAnimationView animationNamed:@"GeometryTransformTest"];
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testAnimationLoaded {
XCTAssertNotNil(self.animationView.sceneModel, @"Animation Composition is nil");
}
- (void)testGeometryCenter {
LOTKeypath *keypath = [LOTKeypath keypathWithKeys:@"Center", @"Ellipse 1", nil];
CGPoint midPoint = CGPointMake(CGRectGetMidX(self.animationView.bounds), CGRectGetMidY(self.animationView.bounds));
CGPoint midPointInChildSpace = [self.animationView convertPoint:midPoint toKeypathLayer:keypath];
CGPoint midPointInParentSpace = [self.animationView convertPoint:CGPointZero fromKeypathLayer:keypath];
XCTAssertTrue((CGPointEqualToPoint(midPointInChildSpace, CGPointZero)), @"Convert to point incorrect");
XCTAssertTrue((CGPointEqualToPoint(midPointInParentSpace, midPoint)), @"Convert from point incorrect");
}
- (void)testGeometryBottomRight {
LOTKeypath *keypath = [LOTKeypath keypathWithKeys:@"BottomRight", @"Ellipse 1", nil];
CGPoint midPoint = CGPointMake(CGRectGetMidX(self.animationView.bounds), CGRectGetMidY(self.animationView.bounds));
CGPoint bottomRightPoint = CGPointMake(CGRectGetMaxX(self.animationView.bounds), CGRectGetMaxY(self.animationView.bounds));
CGPoint midPointInChildSpace = [self.animationView convertPoint:midPoint toKeypathLayer:keypath];
CGPoint midPointInParentSpace = [self.animationView convertPoint:CGPointZero fromKeypathLayer:keypath];
XCTAssertTrue((CGPointEqualToPoint(midPointInChildSpace, CGPointMake(-midPoint.x, -midPoint.y))), @"Convert to point incorrect");
XCTAssertTrue((CGPointEqualToPoint(midPointInParentSpace, bottomRightPoint)), @"Convert from point incorrect");
}
- (void)testGeometryScaled {
LOTKeypath *keypath = [LOTKeypath keypathWithKeys:@"Scaled", @"Ellipse 1", nil];
CGPoint bottomRightPoint = CGPointMake(CGRectGetMaxX(self.animationView.bounds), CGRectGetMaxY(self.animationView.bounds));
CGPoint topLeftInChildSpace = [self.animationView convertPoint:CGPointZero toKeypathLayer:keypath];
CGPoint bottomRightInParentSpace = [self.animationView convertPoint:CGPointMake(75, 75) fromKeypathLayer:keypath];
XCTAssertTrue((CGPointEqualToPoint(bottomRightInParentSpace, bottomRightPoint)), @"Convert to point incorrect");
XCTAssertTrue((CGPointEqualToPoint(topLeftInChildSpace, CGPointMake(-75, -75))), @"Convert from point incorrect");
}
@end

View File

@@ -0,0 +1,127 @@
//
// LAKeypathTest.m
// lottie-ios_Tests
//
// Created by brandon_withrow on 12/14/17.
// Copyright © 2017 Brandon Withrow. All rights reserved.
//
#import <XCTest/XCTest.h>
#import <Lottie/Lottie.h>
@interface LAKeypathTest : XCTestCase
@property (nonatomic, strong) LOTAnimationView *animationView;
@end
@implementation LAKeypathTest
- (void)setUp {
[super setUp];
self.animationView = [LOTAnimationView animationNamed:@"keypathTest"];
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testAnimationLoaded {
XCTAssertNotNil(self.animationView.sceneModel, @"Animation Composition is nil");
}
- (void)testExplicitSearch {
NSString *searchTerm = @"Shape Layer 1.Shape 1.Path 1";
NSArray *results = [self.animationView keysForKeyPath:[LOTKeypath keypathWithString:searchTerm]];
XCTAssertTrue((results.count == 1), @"Wrong number of results");
NSString *firstObject = results.firstObject;
XCTAssertTrue([searchTerm isEqualToString:firstObject], @"Wrong keypath found");
}
- (void)testFuzzyKeySearch_Shape1 {
NSArray *results = [self.animationView keysForKeyPath:[LOTKeypath keypathWithKeys:@"**", @"Shape 1", nil]];
NSArray *expectedResults = @[@"Shape Layer 1.Shape 1",
@"WiggleLayer.Shape 1",
@"GroupShapeLayer.Group 1.Shape 1",
@"TwoShapeLayer.Shape 1",
@"Precomp.DoubleGroupShape.TopGroup.Group 2.Group 1.Shape 1",
@"Precomp.GroupShape.Group 1.Shape 1",
@"Precomp.SingleShape.Shape 1",
@"Precomp.DoubleGroupShape.TopGroup.Group 1.Group 1.Shape 1"];
NSSet *set1 = [NSSet setWithArray:results];
NSSet *set2 = [NSSet setWithArray:expectedResults];
XCTAssertTrue([set1 isEqualToSet:set2], @"Wrong keypath found");
}
- (void)testFuzzyKeySearch_Shape1_Path1 {
NSArray *results = [self.animationView keysForKeyPath:[LOTKeypath keypathWithKeys:@"**", @"Shape 1", @"Path 1", nil]];
NSArray *expectedResults = @[@"GroupShapeLayer.Group 1.Shape 1.Path 1",
@"Shape Layer 1.Shape 1.Path 1",
@"TwoShapeLayer.Shape 1.Path 1",
@"Precomp.DoubleGroupShape.TopGroup.Group 2.Group 1.Shape 1.Path 1",
@"Precomp.GroupShape.Group 1.Shape 1.Path 1",
@"Precomp.SingleShape.Shape 1.Path 1",
@"Precomp.DoubleGroupShape.TopGroup.Group 1.Group 1.Shape 1.Path 1"];
NSSet *set1 = [NSSet setWithArray:results];
NSSet *set2 = [NSSet setWithArray:expectedResults];
XCTAssertTrue([set1 isEqualToSet:set2], @"Wrong keypath found");
}
- (void)testWildcardKeySearch_Shape1 {
NSArray *results = [self.animationView keysForKeyPath:[LOTKeypath keypathWithKeys:@"*", @"Shape 1", nil]];
NSArray *expectedResults = @[@"Shape Layer 1.Shape 1",
@"WiggleLayer.Shape 1",
@"TwoShapeLayer.Shape 1"];
NSSet *set1 = [NSSet setWithArray:results];
NSSet *set2 = [NSSet setWithArray:expectedResults];
XCTAssertTrue([set1 isEqualToSet:set2], @"Wrong keypath found");
}
- (void)testCompoundFuzzyKeySearch_Shape1 {
NSArray *results = [self.animationView keysForKeyPath:[LOTKeypath keypathWithKeys:@"**", @"Shape 1", @"*", @"Stroke Width", nil]];
NSArray *expectedResults = @[@"Shape Layer 1.Shape 1.Stroke 1.Stroke Width",
@"WiggleLayer.Shape 1.Stroke 1.Stroke Width",
@"GroupShapeLayer.Group 1.Shape 1.Stroke 1.Stroke Width",
@"TwoShapeLayer.Shape 1.Stroke 1.Stroke Width"];
NSSet *set1 = [NSSet setWithArray:results];
NSSet *set2 = [NSSet setWithArray:expectedResults];
XCTAssertTrue([set1 isEqualToSet:set2], @"Wrong keypath found");
}
- (void)testDoubleFuzzyKeySearch_Shape1 {
NSArray *results = [self.animationView keysForKeyPath:[LOTKeypath keypathWithKeys:@"**", @"Group 1", @"**", @"Path 1", nil]];
NSArray *expectedResults = @[@"Precomp.DoubleGroupShape.TopGroup.Group 2.Group 1.Shape 1.Path 1",
@"Precomp.GroupShape.Group 1.Shape 2.Path 1",
@"Precomp.GroupShape.Group 1.Shape 1.Path 1",
@"GroupShapeLayer.Group 1.Shape 2.Path 1",
@"GroupShapeLayer.Group 1.Shape 1.Path 1",
@"Precomp.DoubleGroupShape.TopGroup.Group 1.Group 1.Shape 2.Path 1",
@"Precomp.DoubleGroupShape.TopGroup.Group 1.Group 1.Shape 1.Path 1",
@"Precomp.DoubleGroupShape.TopGroup.Group 2.Group 1.Shape 2.Path 1"];
NSSet *set1 = [NSSet setWithArray:results];
NSSet *set2 = [NSSet setWithArray:expectedResults];
XCTAssertTrue([set1 isEqualToSet:set2], @"Wrong keypath found");
}
- (void)testKeySearch_Precomp {
NSArray *results = [self.animationView keysForKeyPath:[LOTKeypath keypathWithKeys:@"Precomp", nil]];
NSArray *expectedResults = @[@"Precomp"];
NSSet *set1 = [NSSet setWithArray:results];
NSSet *set2 = [NSSet setWithArray:expectedResults];
XCTAssertTrue([set1 isEqualToSet:set2], @"Wrong keypath found");
}
- (void)testFuzzyKeySearch_Precomp {
NSArray *results = [self.animationView keysForKeyPath:[LOTKeypath keypathWithKeys:@"Precomp", @"**", nil]];
XCTAssertTrue((results.count == 33), @"Wrong number of results");
}
@end

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"v":"4.12.0","fr":23.9759979248047,"ip":0,"op":48.9999957589018,"w":300,"h":300,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-51],[0,79]],"o":[[0,51],[0,-79]],"v":[[-52.182,-74.182],[32.818,-38.182]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","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":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"n":"0p833_0p833_0p333_0","t":0,"s":[58.182,-52.818],"e":[58.182,102.182],"to":[0,25.8333339691162],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":29,"s":[58.182,102.182],"e":[58.182,-52.818],"to":[0,0],"ti":[0,25.8333339691162]},{"t":47.9999958454548}],"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":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[69.723,69.723],"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":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"n":"0p833_0p833_0p333_0","t":0,"s":[-82.139,-74.139],"e":[-82.139,115.861],"to":[0,0],"ti":[0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":28,"s":[-82.139,115.861],"e":[-82.139,-74.139],"to":[0,0],"ti":[0,0]},{"t":47.9999958454548}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"n":["0p833_0p833_0p333_0"],"t":0,"s":[45],"e":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0p667_1_0p167_0p167"],"t":28,"s":[0],"e":[-45]},{"t":47.9999958454548}],"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":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":48.9999957589018,"st":0,"bm":0}]}

View File

@@ -64,9 +64,16 @@
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 */; };
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 */; };
6289F38A1FE8784200C10B3E /* LAGeometryTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6289F3891FE8784200C10B3E /* LAGeometryTest.m */; };
629EC57F1F54BFF1005B2C59 /* LAControlsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 629EC57E1F54BFF1005B2C59 /* LAControlsViewController.m */; };
629EC5811F54C00B005B2C59 /* Switch.json in Resources */ = {isa = PBXBuildFile; fileRef = 629EC5801F54C00B005B2C59 /* Switch.json */; };
629EC5891F54C925005B2C59 /* Switch_States.json in Resources */ = {isa = PBXBuildFile; fileRef = 629EC5881F54C925005B2C59 /* Switch_States.json */; };
62A62AE81FE2FF2B001A2C2F /* keypathTest.json in Resources */ = {isa = PBXBuildFile; fileRef = 62A62AE71FE2FF2A001A2C2F /* keypathTest.json */; };
62A62AE91FE2FF2B001A2C2F /* keypathTest.json in Resources */ = {isa = PBXBuildFile; fileRef = 62A62AE71FE2FF2A001A2C2F /* keypathTest.json */; };
62A62AEB1FE2FFB0001A2C2F /* LAKeypathTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 62A62AEA1FE2FFB0001A2C2F /* LAKeypathTest.m */; };
62B2546A1E3A8D310035A842 /* LottieRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 62B254631E3A8D310035A842 /* LottieRootViewController.m */; };
62B2546B1E3A8D310035A842 /* AnimationExplorerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 62B254651E3A8D310035A842 /* AnimationExplorerViewController.m */; };
62B2546C1E3A8D310035A842 /* AnimationTransitionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 62B254671E3A8D310035A842 /* AnimationTransitionViewController.m */; };
@@ -169,10 +176,15 @@
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>"; };
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>"; };
629EC57D1F54BFF1005B2C59 /* LAControlsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LAControlsViewController.h; sourceTree = "<group>"; };
629EC57E1F54BFF1005B2C59 /* LAControlsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LAControlsViewController.m; sourceTree = "<group>"; };
629EC5801F54C00B005B2C59 /* Switch.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Switch.json; sourceTree = "<group>"; };
629EC5881F54C925005B2C59 /* Switch_States.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Switch_States.json; sourceTree = "<group>"; };
62A62AE71FE2FF2A001A2C2F /* keypathTest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = keypathTest.json; sourceTree = "<group>"; };
62A62AEA1FE2FFB0001A2C2F /* LAKeypathTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LAKeypathTest.m; sourceTree = "<group>"; };
62B254621E3A8D310035A842 /* LottieRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LottieRootViewController.h; sourceTree = "<group>"; };
62B254631E3A8D310035A842 /* LottieRootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LottieRootViewController.m; sourceTree = "<group>"; };
62B254641E3A8D310035A842 /* AnimationExplorerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationExplorerViewController.h; sourceTree = "<group>"; };
@@ -337,6 +349,8 @@
6003F5B5195388D20070C39A /* Tests */ = {
isa = PBXGroup;
children = (
6289F3891FE8784200C10B3E /* LAGeometryTest.m */,
62A62AEA1FE2FFB0001A2C2F /* LAKeypathTest.m */,
6003F5BB195388D20070C39A /* Tests.m */,
);
path = Tests;
@@ -349,9 +363,12 @@
622F76CF1F2BE63100269858 /* TypeFace */,
622F76B51F2BE58100269858 /* 9squares-AlBoardman.json */,
629EC5801F54C00B005B2C59 /* Switch.json */,
62A62AE71FE2FF2A001A2C2F /* keypathTest.json */,
622F76B61F2BE58100269858 /* HamburgerArrow.json */,
6289F3861FE877FC00C10B3E /* GeometryTransformTest.json */,
622F76B71F2BE58100269858 /* IconTransitions.json */,
622F76B81F2BE58100269858 /* LottieLogo1_masked.json */,
6289F3841FE4A3F500C10B3E /* setValueTest.json */,
622F76BA1F2BE58100269858 /* LottieLogo2.json */,
622F76B91F2BE58100269858 /* LottieLogo1.json */,
622F76BB1F2BE58100269858 /* MotionCorpse-Jrcanest.json */,
@@ -592,6 +609,7 @@
48A852311E3A9E71000AD155 /* lottie_logo.png in Resources */,
622F76F11F2BE63100269858 /* BlinkingCursor.json in Resources */,
622F76C71F2BE58100269858 /* LottieLogo2.json in Resources */,
62A62AE81FE2FF2B001A2C2F /* keypathTest.json in Resources */,
622F76C91F2BE58100269858 /* PinJump.json in Resources */,
622F76F51F2BE63100269858 /* D.json in Resources */,
622F76CD1F2BE58100269858 /* vcTransition2.json in Resources */,
@@ -603,6 +621,7 @@
622F77031F2BE63100269858 /* R.json in Resources */,
71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */,
622F76CA1F2BE58100269858 /* TwitterHeart.json in Resources */,
6289F3871FE877FC00C10B3E /* GeometryTransformTest.json in Resources */,
622F76F91F2BE63100269858 /* H.json in Resources */,
622F76C61F2BE58100269858 /* LottieLogo1.json in Resources */,
622F77051F2BE63100269858 /* T.json in Resources */,
@@ -629,6 +648,7 @@
622F76C51F2BE58100269858 /* LottieLogo1_masked.json in Resources */,
622F76FC1F2BE63100269858 /* K.json in Resources */,
622F76CC1F2BE58100269858 /* vcTransition1.json in Resources */,
6289F3851FE4A3F500C10B3E /* setValueTest.json in Resources */,
622F76FA1F2BE63100269858 /* I.json in Resources */,
622F76F21F2BE63100269858 /* C.json in Resources */,
622F76F81F2BE63100269858 /* G.json in Resources */,
@@ -642,6 +662,8 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
62A62AE91FE2FF2B001A2C2F /* keypathTest.json in Resources */,
6289F3881FE877FC00C10B3E /* GeometryTransformTest.json in Resources */,
6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -820,6 +842,8 @@
buildActionMask = 2147483647;
files = (
6003F5BC195388D20070C39A /* Tests.m in Sources */,
6289F38A1FE8784200C10B3E /* LAGeometryTest.m in Sources */,
62A62AEB1FE2FFB0001A2C2F /* LAKeypathTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1007,7 +1031,7 @@
INFOPLIST_FILE = "Tests/Tests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/lottie-ios_Example.app/lottie-ios_Example";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Lottie-Example.app/Lottie-Example";
WRAPPER_EXTENSION = xctest;
};
name = Debug;
@@ -1027,7 +1051,7 @@
INFOPLIST_FILE = "Tests/Tests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/lottie-ios_Example.app/lottie-ios_Example";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Lottie-Example.app/Lottie-Example";
WRAPPER_EXTENSION = xctest;
};
name = Release;

View File

@@ -101,6 +101,11 @@
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {

View File

@@ -190,6 +190,12 @@
6274D0231F1E830E00E05049 /* LOTTransformInterpolator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6274D0201F1E830E00E05049 /* LOTTransformInterpolator.m */; };
6274D0241F1E830E00E05049 /* LOTTransformInterpolator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6274D0201F1E830E00E05049 /* LOTTransformInterpolator.m */; };
6274D0251F1E830E00E05049 /* LOTTransformInterpolator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6274D0201F1E830E00E05049 /* LOTTransformInterpolator.m */; };
6279981B1FE1D04600B2DDD9 /* LOTKeypath.h in Headers */ = {isa = PBXBuildFile; fileRef = 627998191FE1D04600B2DDD9 /* LOTKeypath.h */; settings = {ATTRIBUTES = (Public, ); }; };
6279981C1FE1D04600B2DDD9 /* LOTKeypath.m in Sources */ = {isa = PBXBuildFile; fileRef = 6279981A1FE1D04600B2DDD9 /* LOTKeypath.m */; };
6279981D1FE1D99F00B2DDD9 /* LOTKeypath.h in Headers */ = {isa = PBXBuildFile; fileRef = 627998191FE1D04600B2DDD9 /* LOTKeypath.h */; settings = {ATTRIBUTES = (Public, ); }; };
6279981E1FE1D9AC00B2DDD9 /* LOTKeypath.m in Sources */ = {isa = PBXBuildFile; fileRef = 6279981A1FE1D04600B2DDD9 /* LOTKeypath.m */; };
6279981F1FE1D9AD00B2DDD9 /* LOTKeypath.m in Sources */ = {isa = PBXBuildFile; fileRef = 6279981A1FE1D04600B2DDD9 /* LOTKeypath.m */; };
627998201FE1D9C800B2DDD9 /* LOTKeypath.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 627998191FE1D04600B2DDD9 /* LOTKeypath.h */; };
6289053E1F33EA0F005154FA /* LOTCacheProvider.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = EE498E3D1F336A4900D1DFCD /* LOTCacheProvider.h */; };
628905411F352472005154FA /* LOTRadialGradientLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 6289053F1F352472005154FA /* LOTRadialGradientLayer.h */; };
628905421F352472005154FA /* LOTRadialGradientLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 6289053F1F352472005154FA /* LOTRadialGradientLayer.h */; };
@@ -204,6 +210,11 @@
629EC5371F50DFFF005B2C59 /* LOTAnimatedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 629EC5361F50DFFF005B2C59 /* LOTAnimatedControl.m */; };
629EC5381F50E00F005B2C59 /* LOTAnimatedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 629EC5361F50DFFF005B2C59 /* LOTAnimatedControl.m */; };
629EC5391F50E02A005B2C59 /* LOTAnimatedControl.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 629EC5321F50DFE4005B2C59 /* LOTAnimatedControl.h */; };
62A62B4A1FE48220001A2C2F /* LOTValueCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 62A62B481FE48220001A2C2F /* LOTValueCallback.h */; };
62A62B4B1FE48220001A2C2F /* LOTValueCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 62A62B481FE48220001A2C2F /* LOTValueCallback.h */; };
62A62B4C1FE48220001A2C2F /* LOTValueCallback.m in Sources */ = {isa = PBXBuildFile; fileRef = 62A62B491FE48220001A2C2F /* LOTValueCallback.m */; };
62A62B4D1FE48220001A2C2F /* LOTValueCallback.m in Sources */ = {isa = PBXBuildFile; fileRef = 62A62B491FE48220001A2C2F /* LOTValueCallback.m */; };
62A62B4E1FE4A1DC001A2C2F /* LOTValueCallback.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 62A62B481FE48220001A2C2F /* LOTValueCallback.h */; };
62BFC2DE1F14298D0068A342 /* LOTAnimatorNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 62BFC2D01F14298D0068A342 /* LOTAnimatorNode.h */; };
62BFC2DF1F14298D0068A342 /* LOTAnimatorNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 62BFC2D01F14298D0068A342 /* LOTAnimatorNode.h */; };
62BFC2E01F14298D0068A342 /* LOTAnimatorNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 62BFC2D11F14298D0068A342 /* LOTAnimatorNode.m */; };
@@ -300,6 +311,8 @@
dstPath = include/Lottie;
dstSubfolderSpec = 16;
files = (
62A62B4E1FE4A1DC001A2C2F /* LOTValueCallback.h in CopyFiles */,
627998201FE1D9C800B2DDD9 /* LOTKeypath.h in CopyFiles */,
629EC5391F50E02A005B2C59 /* LOTAnimatedControl.h in CopyFiles */,
629EC5311F50CC53005B2C59 /* LOTAnimatedSwitch.h in CopyFiles */,
6289053E1F33EA0F005154FA /* LOTCacheProvider.h in CopyFiles */,
@@ -398,12 +411,16 @@
6274D0191F1E82D000E05049 /* LOTLayerContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LOTLayerContainer.m; sourceTree = "<group>"; };
6274D01F1F1E830E00E05049 /* LOTTransformInterpolator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LOTTransformInterpolator.h; path = "lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTTransformInterpolator.h"; sourceTree = SOURCE_ROOT; };
6274D0201F1E830E00E05049 /* LOTTransformInterpolator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LOTTransformInterpolator.m; path = "lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTTransformInterpolator.m"; sourceTree = SOURCE_ROOT; };
627998191FE1D04600B2DDD9 /* LOTKeypath.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LOTKeypath.h; sourceTree = "<group>"; };
6279981A1FE1D04600B2DDD9 /* LOTKeypath.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LOTKeypath.m; sourceTree = "<group>"; };
6289053F1F352472005154FA /* LOTRadialGradientLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LOTRadialGradientLayer.h; sourceTree = "<group>"; };
628905401F352472005154FA /* LOTRadialGradientLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LOTRadialGradientLayer.m; sourceTree = "<group>"; };
629EC52A1F50CBF7005B2C59 /* LOTAnimatedSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LOTAnimatedSwitch.h; sourceTree = "<group>"; };
629EC52E1F50CC2E005B2C59 /* LOTAnimatedSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LOTAnimatedSwitch.m; sourceTree = "<group>"; };
629EC5321F50DFE4005B2C59 /* LOTAnimatedControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LOTAnimatedControl.h; sourceTree = "<group>"; };
629EC5361F50DFFF005B2C59 /* LOTAnimatedControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LOTAnimatedControl.m; sourceTree = "<group>"; };
62A62B481FE48220001A2C2F /* LOTValueCallback.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LOTValueCallback.h; sourceTree = "<group>"; };
62A62B491FE48220001A2C2F /* LOTValueCallback.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LOTValueCallback.m; sourceTree = "<group>"; };
62BFC2D01F14298D0068A342 /* LOTAnimatorNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LOTAnimatorNode.h; path = "lottie-ios/Classes/RenderSystem/LOTAnimatorNode.h"; sourceTree = SOURCE_ROOT; };
62BFC2D11F14298D0068A342 /* LOTAnimatorNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LOTAnimatorNode.m; path = "lottie-ios/Classes/RenderSystem/LOTAnimatorNode.m"; sourceTree = SOURCE_ROOT; };
62BFC2D21F14298D0068A342 /* LOTFillRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LOTFillRenderer.h; path = "lottie-ios/Classes/RenderSystem/RenderNodes/LOTFillRenderer.h"; sourceTree = SOURCE_ROOT; };
@@ -552,12 +569,14 @@
481A4A571E4A7885003CF62B /* Private */ = {
isa = PBXGroup;
children = (
6279981A1FE1D04600B2DDD9 /* LOTKeypath.m */,
629EC5361F50DFFF005B2C59 /* LOTAnimatedControl.m */,
629EC52E1F50CC2E005B2C59 /* LOTAnimatedSwitch.m */,
EE498E3B1F336A3B00D1DFCD /* LOTCacheProvider.m */,
62E27B491F3115AF0098420E /* LOTAnimationCache.m */,
622F77101F2BF6AA00269858 /* LOTComposition.m */,
481A4A581E4A7885003CF62B /* LOTAnimationTransitionController.m */,
62A62B491FE48220001A2C2F /* LOTValueCallback.m */,
481A4A591E4A7885003CF62B /* LOTAnimationView.m */,
481A4A5A1E4A7885003CF62B /* LOTAnimationView_Internal.h */,
);
@@ -702,6 +721,8 @@
2DBA16351B4FA408937A16CE /* LOTAnimationView_Compat.h */,
622F770D1F2BF6A000269858 /* LOTComposition.h */,
FA1F5A9F1E42B52800FF36BF /* LOTAnimationView.h */,
62A62B481FE48220001A2C2F /* LOTValueCallback.h */,
627998191FE1D04600B2DDD9 /* LOTKeypath.h */,
62CA59C41E3C179F002D7188 /* LOTAnimationTransitionController.h */,
629EC52A1F50CBF7005B2C59 /* LOTAnimatedSwitch.h */,
629EC5321F50DFE4005B2C59 /* LOTAnimatedControl.h */,
@@ -725,6 +746,7 @@
622F770E1F2BF6A000269858 /* LOTComposition.h in Headers */,
481A4AAF1E4A7885003CF62B /* LOTModels.h in Headers */,
FA1F5AA01E42B52800FF36BF /* LOTAnimationView.h in Headers */,
6279981B1FE1D04600B2DDD9 /* LOTKeypath.h in Headers */,
481A4A9F1E4A7885003CF62B /* UIColor+Expanded.h in Headers */,
481A4AB51E4A7885003CF62B /* LOTShapeFill.h in Headers */,
621A4F701F2275980065E14F /* LOTTrimPathNode.h in Headers */,
@@ -765,6 +787,7 @@
62BFC2DE1F14298D0068A342 /* LOTAnimatorNode.h in Headers */,
481A4AB11E4A7885003CF62B /* LOTShapeCircle.h in Headers */,
622F75E91F29508D00269858 /* LOTShapeGradientFill.h in Headers */,
62A62B4A1FE48220001A2C2F /* LOTValueCallback.h in Headers */,
628905411F352472005154FA /* LOTRadialGradientLayer.h in Headers */,
62BFC2E31F14298D0068A342 /* LOTFillRenderer.h in Headers */,
62BFC3031F1449380068A342 /* LOTBezierData.h in Headers */,
@@ -806,6 +829,7 @@
481A4AC21E4A7885003CF62B /* LOTShapeRectangle.h in Headers */,
62BFC2F31F14298D0068A342 /* LOTRenderGroup.h in Headers */,
628905421F352472005154FA /* LOTRadialGradientLayer.h in Headers */,
62A62B4B1FE48220001A2C2F /* LOTValueCallback.h in Headers */,
62C9EA441F1FDBF000DE7D07 /* LOTCircleAnimator.h in Headers */,
62BFC3041F1449380068A342 /* LOTBezierData.h in Headers */,
6201FAE71F200B4A00A047C9 /* LOTMaskContainer.h in Headers */,
@@ -818,6 +842,7 @@
622F76361F2A91CA00269858 /* LOTPolystarAnimator.h in Headers */,
481A4AD61E4A7885003CF62B /* LOTAnimationView_Internal.h in Headers */,
FA1F5AA11E42B52800FF36BF /* LOTAnimationView.h in Headers */,
6279981D1FE1D99F00B2DDD9 /* LOTKeypath.h in Headers */,
62BFC2EE1F14298D0068A342 /* LOTPathAnimator.h in Headers */,
62E27B471F31158B0098420E /* LOTAnimationCache.h in Headers */,
62BFC2DF1F14298D0068A342 /* LOTAnimatorNode.h in Headers */,
@@ -988,6 +1013,7 @@
6274CF8D1F16F29200E05049 /* LOTPointInterpolator.m in Sources */,
481A4AC71E4A7885003CF62B /* LOTShapeStroke.m in Sources */,
6274CF9B1F17E92F00E05049 /* LOTSizeInterpolator.m in Sources */,
6279981C1FE1D04600B2DDD9 /* LOTKeypath.m in Sources */,
62BFC2E51F14298D0068A342 /* LOTFillRenderer.m in Sources */,
481A4AA91E4A7885003CF62B /* LOTLayer.m in Sources */,
62C9EA4C1F1FE6C800DE7D07 /* LOTRoundedRectAnimator.m in Sources */,
@@ -998,6 +1024,7 @@
62BFC2F41F14298D0068A342 /* LOTRenderGroup.m in Sources */,
6274CEBB1F157DCD00E05049 /* LOTNumberInterpolator.m in Sources */,
481A4ABB1E4A7885003CF62B /* LOTShapeGroup.m in Sources */,
62A62B4C1FE48220001A2C2F /* LOTValueCallback.m in Sources */,
481A4AAD1E4A7885003CF62B /* LOTMask.m in Sources */,
62BFC2EF1F14298D0068A342 /* LOTPathAnimator.m in Sources */,
622F762E1F2A8CBA00269858 /* LOTShapeStar.m in Sources */,
@@ -1048,6 +1075,7 @@
62C9EA4E1F1FE6C800DE7D07 /* LOTRoundedRectAnimator.m in Sources */,
622F75ED1F29508D00269858 /* LOTShapeGradientFill.m in Sources */,
621A4F741F2275980065E14F /* LOTTrimPathNode.m in Sources */,
6279981F1FE1D9AD00B2DDD9 /* LOTKeypath.m in Sources */,
84FE13081E4C1553009B157C /* UIColor+Expanded.m in Sources */,
621A4F6C1F216DC60065E14F /* LOTBezierPath.m in Sources */,
62BFC2F61F14298D0068A342 /* LOTRenderGroup.m in Sources */,
@@ -1095,6 +1123,7 @@
6274D0101F1D6CE200E05049 /* LOTStrokeRenderer.m in Sources */,
62BFC3061F1449380068A342 /* LOTBezierData.m in Sources */,
62C9EA271F1EB49000DE7D07 /* LOTCompositionContainer.m in Sources */,
6279981E1FE1D9AC00B2DDD9 /* LOTKeypath.m in Sources */,
48183C9F1E54E20B0039F121 /* CGGeometry+LOTAdditions.m in Sources */,
481A4AAE1E4A7885003CF62B /* LOTMask.m in Sources */,
62C9EA461F1FDBF000DE7D07 /* LOTCircleAnimator.m in Sources */,
@@ -1127,6 +1156,7 @@
622F77121F2BF6AA00269858 /* LOTComposition.m in Sources */,
62BFC2F01F14298D0068A342 /* LOTPathAnimator.m in Sources */,
622F76581F2AC70400269858 /* LOTGradientFillRender.m in Sources */,
62A62B4D1FE48220001A2C2F /* LOTValueCallback.m in Sources */,
622F76381F2A91CA00269858 /* LOTPolystarAnimator.m in Sources */,
6274D01D1F1E82D000E05049 /* LOTLayerContainer.m in Sources */,
481A4AAA1E4A7885003CF62B /* LOTLayer.m in Sources */,

BIN
_AeFiles/KeypathTest.aep Normal file

Binary file not shown.

View File

@@ -16,13 +16,37 @@
withLayerGroup:(LOTLayerGroup * _Nullable)childLayerGroup
withAssestGroup:(LOTAssetGroup * _Nullable)assetGroup;
- (nullable NSArray *)keysForKeyPath:(nonnull LOTKeypath *)keypath;
- (CGPoint)convertPoint:(CGPoint)point
toKeypathLayer:(nonnull LOTKeypath *)keypath
withParentLayer:(CALayer *_Nonnull)parent;
- (CGRect)convertRect:(CGRect)rect
toKeypathLayer:(nonnull LOTKeypath *)keypath
withParentLayer:(CALayer *_Nonnull)parent;
- (CGPoint)convertPoint:(CGPoint)point
fromKeypathLayer:(nonnull LOTKeypath *)keypath
withParentLayer:(CALayer *_Nonnull)parent;
- (CGRect)convertRect:(CGRect)rect
fromKeypathLayer:(nonnull LOTKeypath *)keypath
withParentLayer:(CALayer *_Nonnull)parent;
- (void)addSublayer:(nonnull CALayer *)subLayer
toKeypathLayer:(nonnull LOTKeypath *)keypath;
- (void)maskSublayer:(nonnull CALayer *)subLayer
toKeypathLayer:(nonnull LOTKeypath *)keypath;
- (void)addSublayer:(nonnull CALayer *)subLayer
toLayerNamed:(nonnull NSString *)layerName
applyTransform:(BOOL)applyTransform;
applyTransform:(BOOL)applyTransform __deprecated;
- (CGRect)convertRect:(CGRect)rect
fromLayer:(CALayer *_Nonnull)fromlayer
toLayerNamed:(NSString *_Nonnull)layerName;
toLayerNamed:(NSString *_Nonnull)layerName __deprecated;
@property (nonatomic, readonly, nonnull) NSArray<LOTLayerContainer *> *childLayers;
@property (nonatomic, readonly, nonnull) NSDictionary *childMap;

View File

@@ -10,10 +10,15 @@
#import "LOTAsset.h"
#import "CGGeometry+LOTAdditions.h"
#import "LOTHelpers.h"
#import "LOTValueInterpolator.h"
#import "LOTAnimatorNode.h"
#import "LOTRenderNode.h"
#import "LOTRenderGroup.h"
@implementation LOTCompositionContainer {
NSNumber *_frameOffset;
CALayer *DEBUG_Center;
NSMutableDictionary *_keypathCache;
}
- (instancetype)initWithModel:(LOTLayer *)layer
@@ -42,7 +47,7 @@
}
- (void)initializeWithChildGroup:(LOTLayerGroup *)childGroup
withAssetGroup:(LOTAssetGroup *)assetGroup {
withAssetGroup:(LOTAssetGroup *)assetGroup {
NSMutableDictionary *childMap = [NSMutableDictionary dictionary];
NSMutableArray *children = [NSMutableArray array];
NSArray *reversedItems = [[childGroup.layers reverseObjectEnumerator] allObjects];
@@ -92,6 +97,134 @@
if (ENABLE_DEBUG_LOGGING) NSLog(@"-------------------- ------------------------------- --------------------");
}
- (void)setViewportBounds:(CGRect)viewportBounds {
[super setViewportBounds:viewportBounds];
for (LOTLayerContainer *layer in _childLayers) {
layer.viewportBounds = viewportBounds;
}
}
- (void)searchNodesForKeypath:(LOTKeypath * _Nonnull)keypath {
if (self.layerName != nil) {
[super searchNodesForKeypath:keypath];
}
if (self.layerName == nil ||
[keypath pushKey:self.layerName]) {
for (LOTLayerContainer *child in _childLayers) {
[child searchNodesForKeypath:keypath];
}
if (self.layerName != nil) {
[keypath popKey];
}
}
}
- (void)setValueCallback:(nonnull LOTValueCallback *)callbackBlock
forKeypath:(nonnull LOTKeypath *)keypath {
if (self.layerName != nil) {
[super setValueCallback:callbackBlock forKeypath:keypath];
}
if (self.layerName == nil ||
[keypath pushKey:self.layerName]) {
for (LOTLayerContainer *child in _childLayers) {
[child setValueCallback:callbackBlock forKeypath:keypath];
}
if (self.layerName != nil) {
[keypath popKey];
}
}
}
- (nullable NSArray *)keysForKeyPath:(nonnull LOTKeypath *)keypath {
if (_keypathCache == nil) {
_keypathCache = [NSMutableDictionary dictionary];
}
[self searchNodesForKeypath:keypath];
[_keypathCache addEntriesFromDictionary:keypath.searchResults];
return keypath.searchResults.allKeys;
}
- (CALayer *)_layerForKeypath:(nonnull LOTKeypath *)keypath {
LOTAnimatorNode *node = _keypathCache[keypath.absoluteKeypath];
if (node == nil) {
[self keysForKeyPath:keypath];
node = _keypathCache[keypath.absoluteKeypath];
}
if (node == nil) {
NSLog(@"LOTComposition could not find layer for keypath:%@", keypath.absoluteKeypath);
return nil;
}
if (![node isKindOfClass:[LOTRenderNode class]]) {
NSLog(@"LOTComposition: Keypath return non-layer node:%@ ", keypath.absoluteKeypath);
return nil;
}
if ([node isKindOfClass:[LOTRenderGroup class]]) {
return [(LOTRenderGroup *)node containerLayer];
}
LOTRenderNode *renderNode = (LOTRenderNode *)node;
return renderNode.outputLayer;
}
- (CGPoint)convertPoint:(CGPoint)point
toKeypathLayer:(nonnull LOTKeypath *)keypath
withParentLayer:(CALayer *_Nonnull)parent{
CALayer *layer = [self _layerForKeypath:keypath];
if (!layer) {
return CGPointZero;
}
return [parent convertPoint:point toLayer:layer];
}
- (CGRect)convertRect:(CGRect)rect
toKeypathLayer:(nonnull LOTKeypath *)keypath
withParentLayer:(CALayer *_Nonnull)parent{
CALayer *layer = [self _layerForKeypath:keypath];
if (!layer) {
return CGRectZero;
}
return [parent convertRect:rect toLayer:layer];
}
- (CGPoint)convertPoint:(CGPoint)point
fromKeypathLayer:(nonnull LOTKeypath *)keypath
withParentLayer:(CALayer *_Nonnull)parent{
CALayer *layer = [self _layerForKeypath:keypath];
if (!layer) {
return CGPointZero;
}
return [parent convertPoint:point fromLayer:layer];
}
- (CGRect)convertRect:(CGRect)rect
fromKeypathLayer:(nonnull LOTKeypath *)keypath
withParentLayer:(CALayer *_Nonnull)parent{
CALayer *layer = [self _layerForKeypath:keypath];
if (!layer) {
return CGRectZero;
}
return [parent convertRect:rect fromLayer:layer];
}
- (void)addSublayer:(nonnull CALayer *)subLayer
toKeypathLayer:(nonnull LOTKeypath *)keypath {
CALayer *layer = [self _layerForKeypath:keypath];
if (layer) {
[layer addSublayer:subLayer];
}
}
- (void)maskSublayer:(nonnull CALayer *)subLayer
toKeypathLayer:(nonnull LOTKeypath *)keypath {
CALayer *layer = [self _layerForKeypath:keypath];
if (layer) {
[layer.superlayer addSublayer:subLayer];
[layer removeFromSuperlayer];
subLayer.mask = layer;
}
}
# pragma mark - DEPRECATED
- (BOOL)setValue:(nonnull id)value
forKeypath:(nonnull NSString *)keypath
atFrame:(nullable NSNumber *)frame {
@@ -149,13 +282,6 @@
return xRect;
}
- (void)setViewportBounds:(CGRect)viewportBounds {
[super setViewportBounds:viewportBounds];
for (LOTLayerContainer *layer in _childLayers) {
layer.viewportBounds = viewportBounds;
}
}
- (void)logHierarchyKeypathsWithParent:(NSString * _Nullable)parent {
NSString *keypath = parent;
if (parent && self.layerName) {

View File

@@ -9,6 +9,8 @@
#import "LOTPlatformCompat.h"
#import "LOTLayer.h"
#import "LOTLayerGroup.h"
#import "LOTKeypath.h"
#import "LOTValueCallback.h"
@interface LOTLayerContainer : CALayer
@@ -19,15 +21,21 @@
@property (nonatomic, nullable) NSNumber *currentFrame;
@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;
- (void)addAndMaskSublayer:(nonnull CALayer *)subLayer;
- (void)addAndMaskSublayer:(nonnull CALayer *)subLayer __deprecated;
- (BOOL)setValue:(nonnull id)value
forKeypath:(nonnull NSString *)keypath
atFrame:(nullable NSNumber *)frame;
atFrame:(nullable NSNumber *)frame __deprecated;
- (void)logHierarchyKeypathsWithParent:(NSString * _Nullable)parent;
- (void)logHierarchyKeypathsWithParent:(NSString * _Nullable)parent __deprecated;
- (void)searchNodesForKeypath:(LOTKeypath * _Nonnull)keypath;
- (void)setValueCallback:(nonnull LOTValueCallback *)callbackBlock
forKeypath:(nonnull LOTKeypath *)keypath;
@end

View File

@@ -27,7 +27,6 @@
CALayer *DEBUG_Center;
LOTRenderGroup *_contentsGroup;
LOTMaskContainer *_maskLayer;
NSDictionary *_valueInterpolators;
}
@dynamic currentFrame;
@@ -102,6 +101,19 @@
}
NSMutableDictionary *interpolators = [NSMutableDictionary dictionary];
interpolators[@"Opacity"] = _opacityInterpolator;
interpolators[@"Anchor Point"] = _transformInterpolator.anchorInterpolator;
interpolators[@"Scale"] = _transformInterpolator.scaleInterpolator;
interpolators[@"Rotation"] = _transformInterpolator.rotationInterpolator;
if (_transformInterpolator.positionXInterpolator &&
_transformInterpolator.positionYInterpolator) {
interpolators[@"X Position"] = _transformInterpolator.positionXInterpolator;
interpolators[@"Y Position"] = _transformInterpolator.positionYInterpolator;
} else if (_transformInterpolator.positionInterpolator) {
interpolators[@"Position"] = _transformInterpolator.positionInterpolator;
}
// Deprecated
interpolators[@"Transform.Opacity"] = _opacityInterpolator;
interpolators[@"Transform.Anchor Point"] = _transformInterpolator.anchorInterpolator;
interpolators[@"Transform.Scale"] = _transformInterpolator.scaleInterpolator;
@@ -241,6 +253,39 @@
_maskLayer.currentFrame = frame;
}
- (void)setViewportBounds:(CGRect)viewportBounds {
_viewportBounds = viewportBounds;
if (_maskLayer) {
CGPoint center = LOT_RectGetCenterPoint(viewportBounds);
viewportBounds.origin = CGPointMake(-center.x, -center.y);
_maskLayer.bounds = viewportBounds;
}
}
- (void)searchNodesForKeypath:(LOTKeypath * _Nonnull)keypath {
[_contentsGroup searchNodesForKeypath:keypath];
}
- (void)setValueCallback:(nonnull LOTValueCallback *)callbackBlock
forKeypath:(nonnull LOTKeypath *)keypath {
if ([keypath pushKey:self.layerName]) {
// Matches self.
if ([keypath pushKey:@"Transform"]) {
// Is a transform node, check interpolators
LOTValueInterpolator *interpolator = _valueInterpolators[keypath.currentKey];
if (interpolator) {
// We have a match!
[interpolator setValueCallback:callbackBlock];
}
[keypath popKey];
}
[keypath popKey];
}
[_contentsGroup setValueCallback:callbackBlock forKeypath:keypath];
}
# pragma mark - DEPRECATED
- (void)addAndMaskSublayer:(nonnull CALayer *)subLayer {
[_wrapperLayer addSublayer:subLayer];
}
@@ -289,15 +334,6 @@
return NO;
}
- (void)setViewportBounds:(CGRect)viewportBounds {
_viewportBounds = viewportBounds;
if (_maskLayer) {
CGPoint center = LOT_RectGetCenterPoint(viewportBounds);
viewportBounds.origin = CGPointMake(-center.x, -center.y);
_maskLayer.bounds = viewportBounds;
}
}
- (void)logHierarchyKeypathsWithParent:(NSString * _Nullable)parent {
[_contentsGroup logHierarchyKeypathsWithParent:parent];
}

View File

@@ -12,6 +12,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface LOTBezierPath : NSObject
+ (instancetype)pathWithCGPath:(CGPathRef)path;
+ (instancetype)newPath;
- (void)LOT_moveToPoint:(CGPoint)point;

View File

@@ -10,6 +10,7 @@
#import "CGGeometry+LOTAdditions.h"
typedef struct LOT_Subpath LOT_Subpath;
typedef void(^LOTBezierPathEnumerationHandler)(const CGPathElement *element);
struct LOT_Subpath {
CGPathElementType type;
@@ -36,6 +37,12 @@ struct LOT_Subpath {
// MARK - Lifecycle
+ (instancetype)pathWithCGPath:(CGPathRef)path {
LOTBezierPath *returnPath = [LOTBezierPath newPath];
[returnPath setWithCGPath:path];
return returnPath;
}
+ (instancetype)newPath {
return [[LOTBezierPath alloc] init];
}
@@ -281,8 +288,7 @@ struct LOT_Subpath {
CGFloat totalLength = _length;
[self _clearPathData];
LOT_Subpath *subpath = headSubpath_;
headSubpath_ = NULL;
tailSubpath_ = NULL;
@@ -416,4 +422,50 @@ struct LOT_Subpath {
}
}
#pragma mark - From CGPath
- (void)setWithCGPath:(CGPathRef)path {
[self lot_enumeratePath:path elementsUsingBlock:^(const CGPathElement *element) {
switch (element->type) {
case kCGPathElementMoveToPoint: {
CGPoint point = element ->points[0];
[self LOT_moveToPoint:point];
break;
}
case kCGPathElementAddLineToPoint: {
CGPoint point = element ->points[0];
[self LOT_addLineToPoint:point];
break;
}
case kCGPathElementAddQuadCurveToPoint: {
break;
}
case kCGPathElementAddCurveToPoint: {
CGPoint point1 = element->points[0];
CGPoint point2 = element->points[1];
CGPoint point3 = element->points[2];
[self LOT_addCurveToPoint:point3 controlPoint1:point1 controlPoint2:point2];
break;
}
case kCGPathElementCloseSubpath: {
[self LOT_closePath];
break;
}
}
}];
}
- (void)lot_enumeratePath:(CGPathRef)cgPath elementsUsingBlock:(LOTBezierPathEnumerationHandler)handler {
void CGPathEnumerationCallback(void *info, const CGPathElement *element);
CGPathApply(cgPath, (__bridge void * _Nullable)(handler), CGPathEnumerationCallback);
}
@end
void CGPathEnumerationCallback(void *info, const CGPathElement *element)
{
LOTBezierPathEnumerationHandler handler = (__bridge LOTBezierPathEnumerationHandler)(info);
if (handler) {
handler(element);
}
}

View File

@@ -24,7 +24,6 @@ static NSString * const kCompContainerAnimationKey = @"play";
CGFloat _playRangeEndProgress;
NSBundle *_bundle;
CGFloat _animationProgress;
// Properties for tracking automatic restoration of animation.
BOOL _shouldRestoreStateWhenAttachedToWindow;
LOTAnimationCompletionBlock _completionBlockToRestoreWhenAttachedToWindow;
@@ -159,9 +158,6 @@ static NSString * const kCompContainerAnimationKey = @"play";
_sceneModel = model;
_compContainer = [[LOTCompositionContainer alloc] initWithModel:nil inLayerGroup:nil withLayerGroup:_sceneModel.layerGroup withAssestGroup:_sceneModel.assetGroup];
[self.layer addSublayer:_compContainer];
if (ENABLE_DEBUG_LOGGING) {
[self logHierarchyKeypaths];
}
[self _restoreState];
[self setNeedsLayout];
}
@@ -414,66 +410,97 @@ static NSString * const kCompContainerAnimationKey = @"play";
}
}
# pragma mark - External Methods - Other
# pragma mark - External Methods - Interactive Controls
- (void)setValueCallback:(nonnull LOTValueCallback *)callbackBlock
forKeypath:(nonnull LOTKeypath *)keypath {
[_compContainer setValueCallback:callbackBlock forKeypath:keypath];
[self _layoutAndForceUpdate];
}
- (nullable NSArray *)keysForKeyPath:(nonnull LOTKeypath *)keypath {
return [_compContainer keysForKeyPath:keypath];
}
- (CGPoint)convertPoint:(CGPoint)point
toKeypathLayer:(nonnull LOTKeypath *)keypath {
[self _layoutAndForceUpdate];
return [_compContainer convertPoint:point toKeypathLayer:keypath withParentLayer:self.layer];
}
- (CGRect)convertRect:(CGRect)rect
toKeypathLayer:(nonnull LOTKeypath *)keypath {
[self _layoutAndForceUpdate];
return [_compContainer convertRect:rect toKeypathLayer:keypath withParentLayer:self.layer];
}
- (CGPoint)convertPoint:(CGPoint)point
fromKeypathLayer:(nonnull LOTKeypath *)keypath {
[self _layoutAndForceUpdate];
return [_compContainer convertPoint:point fromKeypathLayer:keypath withParentLayer:self.layer];
}
- (CGRect)convertRect:(CGRect)rect
fromKeypathLayer:(nonnull LOTKeypath *)keypath {
[self _layoutAndForceUpdate];
return [_compContainer convertRect:rect fromKeypathLayer:keypath withParentLayer:self.layer];
}
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
- (void)addSubview:(nonnull LOTView *)view
toLayerNamed:(nonnull NSString *)layer
applyTransform:(BOOL)applyTransform {
[self _layout];
toKeypathLayer:(nonnull LOTKeypath *)keypath {
[self _layoutAndForceUpdate];
CGRect viewRect = view.frame;
LOTView *wrapperView = [[LOTView alloc] initWithFrame:viewRect];
view.frame = view.bounds;
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[wrapperView addSubview:view];
[self addSubview:wrapperView];
[_compContainer addSublayer:wrapperView.layer toLayerNamed:layer applyTransform:applyTransform];
[_compContainer addSublayer:wrapperView.layer toKeypathLayer:keypath];
}
- (void)maskSubview:(nonnull LOTView *)view
toKeypathLayer:(nonnull LOTKeypath *)keypath {
[self _layoutAndForceUpdate];
CGRect viewRect = view.frame;
LOTView *wrapperView = [[LOTView alloc] initWithFrame:viewRect];
view.frame = view.bounds;
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[wrapperView addSubview:view];
[self addSubview:wrapperView];
[_compContainer maskSublayer:wrapperView.layer toKeypathLayer:keypath];
}
#else
- (void)addSubview:(nonnull LOTView *)view
toLayerNamed:(nonnull NSString *)layer
applyTransform:(BOOL)applyTransform {
toKeypathLayer:(nonnull LOTKeypath *)keypath {
[self _layout];
CGRect viewRect = view.frame;
LOTView *wrapperView = [[LOTView alloc] initWithFrame:viewRect];
view.frame = view.bounds;
view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[wrapperView addSubview:view];
[self addSubview:wrapperView];
[_compContainer addSublayer:wrapperView.layer toLayerNamed:layer applyTransform:applyTransform];
[_compContainer addSublayer:wrapperView.layer toKeypathLayer:keypath];
}
- (void)maskSubview:(nonnull LOTView *)view
toKeypathLayer:(nonnull LOTKeypath *)keypath {
[self _layout];
CGRect viewRect = view.frame;
LOTView *wrapperView = [[LOTView alloc] initWithFrame:viewRect];
view.frame = view.bounds;
view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[wrapperView addSubview:view];
[self addSubview:wrapperView];
[_compContainer maskSublayer:wrapperView.layer toKeypathLayer:keypath];
}
#endif
- (CGRect)convertRect:(CGRect)rect
toLayerNamed:(NSString *_Nullable)layerName {
[self _layout];
if (layerName == nil) {
return [self.layer convertRect:rect toLayer:_compContainer];
}
return [_compContainer convertRect:rect fromLayer:self.layer toLayerNamed:layerName];
}
- (void)setValue:(nonnull id)value
forKeypath:(nonnull NSString *)keypath
atFrame:(nullable NSNumber *)frame{
BOOL didUpdate = [_compContainer setValue:value forKeypath:keypath atFrame:frame];
if (didUpdate) {
[CATransaction begin];
[CATransaction setDisableActions:YES];
[_compContainer displayWithFrame:_compContainer.currentFrame forceUpdate:YES];
[CATransaction commit];
} else {
NSLog(@"%s: Keypath Not Found: %@", __PRETTY_FUNCTION__, keypath);
}
}
- (void)logHierarchyKeypaths {
[_compContainer logHierarchyKeypathsWithParent:nil];
}
# pragma mark - Semi-Private Methods
- (CALayer * _Nullable)layerForKey:(NSString * _Nonnull)keyname {
@@ -615,6 +642,14 @@ static NSString * const kCompContainerAnimationKey = @"play";
#endif
- (void)_layoutAndForceUpdate {
[CATransaction begin];
[CATransaction setDisableActions:YES];
[self _layout];
[_compContainer displayWithFrame:_compContainer.currentFrame forceUpdate:YES];
[CATransaction commit];
}
- (void)_layout {
CGPoint centerPoint = LOT_RectGetCenterPoint(self.bounds);
CATransform3D xform;
@@ -671,4 +706,68 @@ static NSString * const kCompContainerAnimationKey = @"play";
}
}
# pragma mark - DEPRECATED
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
- (void)addSubview:(nonnull LOTView *)view
toLayerNamed:(nonnull NSString *)layer
applyTransform:(BOOL)applyTransform {
NSLog(@"%s: Function is DEPRECATED. Please use addSubview:forKeypathLayer:", __PRETTY_FUNCTION__);
[self _layout];
CGRect viewRect = view.frame;
LOTView *wrapperView = [[LOTView alloc] initWithFrame:viewRect];
view.frame = view.bounds;
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[wrapperView addSubview:view];
[self addSubview:wrapperView];
[_compContainer addSublayer:wrapperView.layer toLayerNamed:layer applyTransform:applyTransform];
}
#else
- (void)addSubview:(nonnull LOTView *)view
toLayerNamed:(nonnull NSString *)layer
applyTransform:(BOOL)applyTransform {
NSLog(@"%s: Function is DEPRECATED. Please use addSubview:forKeypathLayer:", __PRETTY_FUNCTION__);
CGRect viewRect = view.frame;
LOTView *wrapperView = [[LOTView alloc] initWithFrame:viewRect];
view.frame = view.bounds;
view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[wrapperView addSubview:view];
[self addSubview:wrapperView];
[_compContainer addSublayer:wrapperView.layer toLayerNamed:layer applyTransform:applyTransform];
}
#endif
- (CGRect)convertRect:(CGRect)rect
toLayerNamed:(NSString *_Nullable)layerName {
NSLog(@"%s: Function is DEPRECATED. Please use convertRect:forKeypathLayer:", __PRETTY_FUNCTION__);
[self _layout];
if (layerName == nil) {
return [self.layer convertRect:rect toLayer:_compContainer];
}
return [_compContainer convertRect:rect fromLayer:self.layer toLayerNamed:layerName];
}
- (void)setValue:(nonnull id)value
forKeypath:(nonnull NSString *)keypath
atFrame:(nullable NSNumber *)frame{
NSLog(@"%s: Function is DEPRECATED. Please use setValueCallback:forKeypath:", __PRETTY_FUNCTION__);
BOOL didUpdate = [_compContainer setValue:value forKeypath:keypath atFrame:frame];
if (didUpdate) {
[CATransaction begin];
[CATransaction setDisableActions:YES];
[_compContainer displayWithFrame:_compContainer.currentFrame forceUpdate:YES];
[CATransaction commit];
} else {
NSLog(@"%s: Keypath Not Found: %@", __PRETTY_FUNCTION__, keypath);
}
}
- (void)logHierarchyKeypaths {
[_compContainer logHierarchyKeypathsWithParent:nil];
}
@end

View File

@@ -0,0 +1,140 @@
//
// LOTKeypath.m
// Lottie_iOS
//
// Created by brandon_withrow on 12/13/17.
// Copyright © 2017 Airbnb. All rights reserved.
//
#import "LOTKeypath.h"
NSString *const kLOTKeypathEnd = @"LOTENDKEYPATH";
@implementation LOTKeypath {
NSInteger _currentDepth;
NSMutableArray<NSNumber *> *_fuzzyDepthStack;
NSMutableArray *_currentStack;
NSArray *_keys;
NSMutableDictionary *_searchResults;
}
+ (nonnull LOTKeypath *)keypathWithString:(nonnull NSString *)keypath {
return [[LOTKeypath alloc] initWithKeys:[keypath componentsSeparatedByString:@"."]];
}
+ (nonnull LOTKeypath *)keypathWithKeys:(nonnull NSString *)firstKey, ... {
NSMutableArray *keys = [NSMutableArray array];
va_list args;
va_start(args, firstKey);
for (NSString *arg = firstKey; arg != nil; arg = va_arg(args, NSString*))
{
[keys addObject:arg];
}
va_end(args);
return [[LOTKeypath alloc] initWithKeys:keys];
}
- (instancetype)initWithKeys:(NSArray *)keys {
self = [super init];
if (self) {
_keys = [NSArray arrayWithArray:keys];
NSMutableString *absolutePath = [NSMutableString string];
for (int i = 0; i < _keys.count; i++) {
if (i > 0) {
[absolutePath appendString:@"."];
}
[absolutePath appendString:_keys[i]];
}
_currentStack = [NSMutableArray array];
_absoluteKeypath = absolutePath;
_currentDepth = 0;
_fuzzyDepthStack = [NSMutableArray array];
_searchResults = [NSMutableDictionary dictionary];
}
return self;
}
- (BOOL)pushKey:(nonnull NSString *)key {
if (_currentDepth == _keys.count &&
self.hasFuzzyWildcard == NO) {
return NO;
}
NSString *current = self.currentKey;
if (self.hasWildcard ||
[current isEqualToString:key]) {
[_currentStack addObject:[key copy]];
_currentDepth ++;
if (self.hasFuzzyWildcard) {
[_fuzzyDepthStack addObject:@(_currentDepth)];
}
return YES;
} else if (self.hasFuzzyWildcard) {
[_currentStack addObject:[key copy]];
return YES;
}
return NO;
}
- (void)popKey {
if (_currentDepth == 0) {
return;
}
NSInteger stackCount = _currentStack.count;
[_currentStack removeLastObject];
if (self.hasFuzzyWildcard ) {
if (stackCount == _fuzzyDepthStack.lastObject.integerValue) {
[_fuzzyDepthStack removeLastObject];
} else {
return;
}
}
_currentDepth --;
}
- (void)popToRootKey {
_currentDepth = 0;
[_currentStack removeAllObjects];
[_fuzzyDepthStack removeAllObjects];
}
- (NSString *)currentKey {
if (_currentDepth == _keys.count) {
return kLOTKeypathEnd;
}
return _keys[_currentDepth];
}
- (NSString *)currentKeyPath {
return [_currentStack componentsJoinedByString:@"."];
}
- (BOOL)hasWildcard {
if (_currentDepth == _keys.count) {
return NO;
}
return ([_keys[_currentDepth] isEqualToString:@"**"] ||
[_keys[_currentDepth] isEqualToString:@"*"]);
}
- (BOOL)hasFuzzyWildcard {
if (_currentDepth == 0 ||
_currentDepth > _keys.count) {
return NO;
}
return [_keys[_currentDepth - 1] isEqualToString:@"**"];
}
- (BOOL)endOfKeypath {
return (_currentDepth == _keys.count);
}
- (void)addSearchResultForCurrentPath:(id _Nonnull)result {
[_searchResults setObject:result forKey:self.currentKeyPath];
}
- (NSDictionary *)searchResults {
return _searchResults;
}
@end

View File

@@ -0,0 +1,63 @@
//
// LOTValueCallback.m
// Lottie
//
// Created by brandon_withrow on 12/15/17.
// Copyright © 2017 Airbnb. All rights reserved.
//
#import "LOTValueCallback.h"
@implementation LOTValueCallback
@end
@implementation LOTColorValueCallback
+ (instancetype)withBlock:(LOTColorValueCallbackBlock)block {
LOTColorValueCallback *colorCallback = [[LOTColorValueCallback alloc] init];
colorCallback.callback = block;
return colorCallback;
}
@end
@implementation LOTNumberValueCallback
+ (instancetype)withBlock:(LOTNumberValueCallbackBlock)block {
LOTNumberValueCallback *numberCallback = [[LOTNumberValueCallback alloc] init];
numberCallback.callback = block;
return numberCallback;
}
@end
@implementation LOTPointValueCallback
+ (instancetype)withBlock:(LOTPointValueCallbackBlock)block {
LOTPointValueCallback *callback = [[LOTPointValueCallback alloc] init];
callback.callback = block;
return callback;
}
@end
@implementation LOTSizeValueCallback
+ (instancetype)withBlock:(LOTSizeValueCallbackBlock)block {
LOTSizeValueCallback *callback = [[LOTSizeValueCallback alloc] init];
callback.callback = block;
return callback;
}
@end
@implementation LOTPathValueCallback
+ (instancetype)withBlock:(LOTPathValueCallbackBlock)block {
LOTPathValueCallback *callback = [[LOTPathValueCallback alloc] init];
callback.callback = block;
return callback;
}
@end

View File

@@ -9,6 +9,8 @@
#import <Foundation/Foundation.h>
#import "LOTAnimationView_Compat.h"
#import "LOTComposition.h"
#import "LOTKeypath.h"
#import "LOTValueCallback.h"
typedef void (^LOTAnimationCompletionBlock)(BOOL animationFinished);
@@ -66,7 +68,7 @@ typedef void (^LOTAnimationCompletionBlock)(BOOL animationFinished);
@property (nonatomic, strong, nullable) LOTComposition *sceneModel;
/*
* Plays the animation from its current position to a specific progress.
* Plays the animation from its current position to a specific progress.
* The animation will start from its current position.
* If loopAnimation is YES the animation will loop from start position to toProgress indefinitely.
* If loopAnimation is NO the animation will stop and the comletion block will be called.
@@ -94,7 +96,7 @@ typedef void (^LOTAnimationCompletionBlock)(BOOL animationFinished);
withCompletion:(nullable LOTAnimationCompletionBlock)completion;
/*
* Plays the animation from specific frame to a specific frame.
* Plays the animation from specific frame to a specific frame.
* The animation will start from its current position.
* If loopAnimation is YES the animation will loop start frame to end frame indefinitely.
* If loopAnimation is NO the animation will stop and the comletion block will be called.
@@ -132,35 +134,35 @@ typedef void (^LOTAnimationCompletionBlock)(BOOL animationFinished);
* @param keypath NSString . separate keypath
* The Keypath is a dot seperated key path that specifies the location of the key to
* be set from the After Effects file. This will begin with the Layer Name.
* EG "Layer 1.Shape 1.Fill 1.Color"
* EG "Layer 1.Shape 1.Fill 1.Color"
*
* @param frame
* The frame is the frame to be set.
* If the keyframe exists it will be overwritten, if it does not exist a new
* The frame is the frame to be set.
* If the keyframe exists it will be overwritten, if it does not exist a new
* Linearlly interpolated keyframe will be added
**/
- (void)setValue:(nonnull id)value
forKeypath:(nonnull NSString *)keypath
atFrame:(nullable NSNumber *)frame;
atFrame:(nullable NSNumber *)frame __deprecated;
/// Logs all child keypaths
- (void)logHierarchyKeypaths;
- (void)logHierarchyKeypaths __deprecated;
/**
* Adds a custom subview to the animation using a LayerName from After Effects
* Adds a custom subview to the animation using a LayerName from After Effects
* as a reference point.
*
* @param view The custom view instance to be added
*
* @param layer The string name of the After Effects layer to be referenced.
*
* @param applyTransform If YES the custom view will be animated to move with the
* @param applyTransform If YES the custom view will be animated to move with the
* specified After Effects layer.
* If NO the custom view will be masked by the After Effects layer
**/
- (void)addSubview:(nonnull LOTView *)view
toLayerNamed:(nonnull NSString *)layer
applyTransform:(BOOL)applyTransform;
applyTransform:(BOOL)applyTransform __deprecated;
/**
* Converts the given CGRect from the recieving animation view's coordinate space
@@ -171,7 +173,30 @@ typedef void (^LOTAnimationCompletionBlock)(BOOL animationFinished);
**/
- (CGRect)convertRect:(CGRect)rect
toLayerNamed:(NSString *_Nullable)layerName;
toLayerNamed:(NSString *_Nullable)layerName __deprecated;
- (void)setValueCallback:(nonnull LOTValueCallback *)callback
forKeypath:(nonnull LOTKeypath *)keypath;
- (nullable NSArray *)keysForKeyPath:(nonnull LOTKeypath *)keypath;
- (CGPoint)convertPoint:(CGPoint)point
toKeypathLayer:(nonnull LOTKeypath *)keypath;
- (CGRect)convertRect:(CGRect)rect
toKeypathLayer:(nonnull LOTKeypath *)keypath;
- (CGPoint)convertPoint:(CGPoint)point
fromKeypathLayer:(nonnull LOTKeypath *)keypath;
- (CGRect)convertRect:(CGRect)rect
fromKeypathLayer:(nonnull LOTKeypath *)keypath;
- (void)addSubview:(nonnull LOTView *)view
toKeypathLayer:(nonnull LOTKeypath *)keypath;
- (void)maskSubview:(nonnull LOTView *)view
toKeypathLayer:(nonnull LOTKeypath *)keypath;
#if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
@property (nonatomic) LOTViewContentMode contentMode;

View File

@@ -0,0 +1,36 @@
//
// LOTKeypath.h
// Lottie_iOS
//
// Created by brandon_withrow on 12/13/17.
// Copyright © 2017 Airbnb. All rights reserved.
//
#import <Foundation/Foundation.h>
extern NSString * _Nonnull const kLOTKeypathEnd;
@interface LOTKeypath : NSObject
+ (nonnull LOTKeypath *)keypathWithString:(nonnull NSString *)keypath;
+ (nonnull LOTKeypath *)keypathWithKeys:(nonnull NSString *)firstKey, ...
NS_REQUIRES_NIL_TERMINATION;
@property (nonatomic, readonly, nonnull) NSString *absoluteKeypath;
@property (nonatomic, readonly, nonnull) NSString *currentKey;
@property (nonatomic, readonly, nonnull) NSString *currentKeyPath;
@property (nonatomic, readonly, nonnull) NSDictionary *searchResults;
@property (nonatomic, readonly) BOOL hasFuzzyWildcard;
@property (nonatomic, readonly) BOOL hasWildcard;
@property (nonatomic, readonly) BOOL endOfKeypath;
- (BOOL)pushKey:(nonnull NSString *)key;
- (void)popKey;
- (void)popToRootKey;
- (void)addSearchResultForCurrentPath:(id _Nonnull)result;
@end

View File

@@ -0,0 +1,94 @@
//
// LOTValueCallback.h
// Lottie
//
// Created by brandon_withrow on 12/15/17.
// Copyright © 2017 Airbnb. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "LOTPlatformCompat.h"
typedef UIColor * _Nonnull (^LOTColorValueCallbackBlock)(CGFloat startFrame,
CGFloat endFrame,
UIColor * _Nullable startColor,
UIColor * _Nullable endColor,
UIColor * _Nullable interpolatedColor,
CGFloat interpolatedProgress,
CGFloat currentFrame);
typedef CGFloat (^LOTNumberValueCallbackBlock)(CGFloat startFrame,
CGFloat endFrame,
CGFloat startValue,
CGFloat endValue,
CGFloat interpolatedValue,
CGFloat interpolatedProgress,
CGFloat currentFrame);
typedef CGPoint (^LOTPointValueCallbackBlock)(CGFloat startFrame,
CGFloat endFrame,
CGPoint startPoint,
CGPoint endPoint,
CGPoint interpolatedPoint,
CGFloat interpolatedProgress,
CGFloat currentFrame);
typedef CGSize (^LOTSizeValueCallbackBlock)(CGFloat startFrame,
CGFloat endFrame,
CGSize startSize,
CGSize endSize,
CGSize interpolatedSize,
CGFloat interpolatedProgress,
CGFloat currentFrame);
typedef UIBezierPath * _Nonnull (^LOTPathValueCallbackBlock)(CGFloat startFrame,
CGFloat endFrame,
CGFloat interpolatedProgress,
CGFloat currentFrame);
@interface LOTValueCallback : NSObject
@end
@interface LOTColorValueCallback : LOTValueCallback
+ (instancetype _Nonnull)withBlock:(LOTColorValueCallbackBlock _Nonnull )block;
@property (nonatomic, copy, nonnull) LOTColorValueCallbackBlock callback;
@end
@interface LOTNumberValueCallback : LOTValueCallback
+ (instancetype _Nonnull)withBlock:(LOTNumberValueCallbackBlock _Nonnull)block;
@property (nonatomic, copy, nonnull) LOTNumberValueCallbackBlock callback;
@end
@interface LOTPointValueCallback : LOTValueCallback
+ (instancetype _Nonnull)withBlock:(LOTPointValueCallbackBlock _Nonnull)block;
@property (nonatomic, copy, nonnull) LOTPointValueCallbackBlock callback;
@end
@interface LOTSizeValueCallback : LOTValueCallback
+ (instancetype _Nonnull)withBlock:(LOTSizeValueCallbackBlock _Nonnull)block;
@property (nonatomic, copy, nonnull) LOTSizeValueCallbackBlock callback;
@end
@interface LOTPathValueCallback : LOTValueCallback
+ (instancetype _Nonnull)withBlock:(LOTPathValueCallbackBlock _Nonnull)block;
@property (nonatomic, copy, nonnull) LOTPathValueCallbackBlock callback;
@end

View File

@@ -8,6 +8,7 @@
#import "LOTValueInterpolator.h"
#import "LOTPlatformCompat.h"
#import "LOTValueCallback.h"
NS_ASSUME_NONNULL_BEGIN
@@ -15,6 +16,8 @@ NS_ASSUME_NONNULL_BEGIN
- (UIColor *)colorForFrame:(NSNumber *)frame;
@property (nonatomic, strong, nullable) LOTColorValueCallback *colorCallback;
@end
NS_ASSUME_NONNULL_END

View File

@@ -14,13 +14,19 @@
- (UIColor *)colorForFrame:(NSNumber *)frame {
CGFloat progress = [self progressForFrame:frame];
UIColor *returnColor;
if (progress == 0) {
return self.leadingKeyframe.colorValue;
returnColor = self.leadingKeyframe.colorValue;
} else if (progress == 1) {
returnColor = self.trailingKeyframe.colorValue;
} else {
returnColor = [UIColor LOT_colorByLerpingFromColor:self.leadingKeyframe.colorValue toColor:self.trailingKeyframe.colorValue amount:progress];
}
if (progress == 1) {
return self.trailingKeyframe.colorValue;
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);
}
UIColor *returnColor = [UIColor LOT_colorByLerpingFromColor:self.leadingKeyframe.colorValue toColor:self.trailingKeyframe.colorValue amount:progress];
return returnColor;
}
@@ -32,4 +38,13 @@
return nil;
}
- (void)setValueCallback:(LOTValueCallback *)valueCallback {
NSAssert(([valueCallback isKindOfClass:[LOTColorValueCallback class]]), @"Color Interpolator set with incorrect callback type. Expected LOTColorValueCallback");
self.colorCallback = (LOTColorValueCallback *)valueCallback;
}
- (BOOL)hasValueOverride {
return self.colorCallback != nil;
}
@end

View File

@@ -8,12 +8,15 @@
#import <Foundation/Foundation.h>
#import "LOTValueInterpolator.h"
#import "LOTValueCallback.h"
NS_ASSUME_NONNULL_BEGIN
@interface LOTNumberInterpolator : LOTValueInterpolator
- (CGFloat)floatValueForFrame:(NSNumber *)frame;
@property (nonatomic, strong, nullable) LOTNumberValueCallback *numberCallback;
@end
NS_ASSUME_NONNULL_END

View File

@@ -13,13 +13,28 @@
- (CGFloat)floatValueForFrame:(NSNumber *)frame {
CGFloat progress = [self progressForFrame:frame];
CGFloat returnValue;
if (progress == 0) {
return self.leadingKeyframe.floatValue;
returnValue = self.leadingKeyframe.floatValue;
} else if (progress == 1) {
returnValue = self.trailingKeyframe.floatValue;
} else {
returnValue = LOT_RemapValue(progress, 0, 1, self.leadingKeyframe.floatValue, self.trailingKeyframe.floatValue);
}
if (progress == 1) {
return self.trailingKeyframe.floatValue;
if (self.hasValueOverride) {
return self.numberCallback.callback(self.leadingKeyframe.keyframeTime.floatValue, self.trailingKeyframe.keyframeTime.floatValue, self.leadingKeyframe.floatValue, self.trailingKeyframe.floatValue, returnValue, progress, frame.floatValue);
}
return LOT_RemapValue(progress, 0, 1, self.leadingKeyframe.floatValue, self.trailingKeyframe.floatValue);
return returnValue;
}
- (BOOL)hasValueOverride {
return self.numberCallback != nil;
}
- (void)setValueCallback:(LOTValueCallback *)valueCallback {
NSAssert(([valueCallback isKindOfClass:[LOTNumberValueCallback class]]), @"Number Interpolator set with incorrect callback type. Expected LOTNumberValueCallback");
self.numberCallback = (LOTNumberValueCallback*)valueCallback;
}
- (id)keyframeDataForValue:(id)value {

View File

@@ -9,6 +9,7 @@
#import "LOTValueInterpolator.h"
#import "LOTPlatformCompat.h"
#import "LOTBezierPath.h"
#import "LOTValueCallback.h"
NS_ASSUME_NONNULL_BEGIN
@@ -16,6 +17,8 @@ NS_ASSUME_NONNULL_BEGIN
- (LOTBezierPath *)pathForFrame:(NSNumber *)frame cacheLengths:(BOOL)cacheLengths;
@property (nonatomic, strong, nullable) LOTPathValueCallback *pathCallback;
@end
NS_ASSUME_NONNULL_END

View File

@@ -13,7 +13,11 @@
- (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];
}
LOTBezierPath *returnPath = [[LOTBezierPath alloc] init];
returnPath.cacheLengths = cacheLengths;
LOTBezierData *leadingData = self.leadingKeyframe.pathData;
@@ -62,4 +66,13 @@
return returnPath;
}
- (void)setValueCallback:(LOTValueCallback *)valueCallback {
NSAssert(([valueCallback isKindOfClass:[LOTPathValueCallback class]]), @"Path Interpolator set with incorrect callback type. Expected LOTPathValueCallback");
self.pathCallback = (LOTPathValueCallback*)valueCallback;
}
- (BOOL)hasValueOverride {
return self.pathCallback != nil;
}
@end

View File

@@ -7,6 +7,7 @@
//
#import "LOTValueInterpolator.h"
#import "LOTValueCallback.h"
NS_ASSUME_NONNULL_BEGIN
@@ -14,6 +15,8 @@ NS_ASSUME_NONNULL_BEGIN
- (CGPoint)pointValueForFrame:(NSNumber *)frame;
@property (nonatomic, strong, nullable) LOTPointValueCallback *pointCallback;
@end
NS_ASSUME_NONNULL_END

View File

@@ -13,20 +13,33 @@
- (CGPoint)pointValueForFrame:(NSNumber *)frame {
CGFloat progress = [self progressForFrame:frame];
CGPoint returnPoint;
if (progress == 0) {
return self.leadingKeyframe.pointValue;
}
if (progress == 1) {
return self.trailingKeyframe.pointValue;
}
if (!CGPointEqualToPoint(self.leadingKeyframe.spatialOutTangent, CGPointZero) &&
!CGPointEqualToPoint(self.trailingKeyframe.spatialInTangent, CGPointZero)) {
returnPoint = self.leadingKeyframe.pointValue;
} else if (progress == 1) {
returnPoint = self.trailingKeyframe.pointValue;
} else if (!CGPointEqualToPoint(self.leadingKeyframe.spatialOutTangent, CGPointZero) ||
!CGPointEqualToPoint(self.trailingKeyframe.spatialInTangent, CGPointZero)) {
// Spatial Bezier path
CGPoint outTan = LOT_PointAddedToPoint(self.leadingKeyframe.pointValue, self.leadingKeyframe.spatialOutTangent);
CGPoint inTan = LOT_PointAddedToPoint(self.trailingKeyframe.pointValue, self.trailingKeyframe.spatialInTangent);
return LOT_PointInCubicCurve(self.leadingKeyframe.pointValue, outTan, inTan, self.trailingKeyframe.pointValue, progress);
returnPoint = LOT_PointInCubicCurve(self.leadingKeyframe.pointValue, outTan, inTan, self.trailingKeyframe.pointValue, progress);
} else {
returnPoint = LOT_PointInLine(self.leadingKeyframe.pointValue, self.trailingKeyframe.pointValue, progress);
}
return LOT_PointInLine(self.leadingKeyframe.pointValue, self.trailingKeyframe.pointValue, progress);
if (self.hasValueOverride) {
return self.pointCallback.callback(self.leadingKeyframe.keyframeTime.floatValue, self.trailingKeyframe.keyframeTime.floatValue, self.leadingKeyframe.pointValue, self.trailingKeyframe.pointValue, returnPoint, progress, frame.floatValue);
}
return returnPoint;
}
- (BOOL)hasValueOverride {
return self.pointCallback != nil;
}
- (void)setValueCallback:(LOTValueCallback *)valueCallback {
NSAssert(([valueCallback isKindOfClass:[LOTPointValueCallback class]]), @"Point Interpolator set with incorrect callback type. Expected LOTPointValueCallback");
self.pointCallback = (LOTPointValueCallback*)valueCallback;
}
- (id)keyframeDataForValue:(id)value {

View File

@@ -7,6 +7,7 @@
//
#import "LOTValueInterpolator.h"
#import "LOTValueCallback.h"
NS_ASSUME_NONNULL_BEGIN
@@ -14,6 +15,8 @@ NS_ASSUME_NONNULL_BEGIN
- (CGSize)sizeValueForFrame:(NSNumber *)frame;
@property (nonatomic, strong, nullable) LOTSizeValueCallback *sizeCallback;
@end
NS_ASSUME_NONNULL_END

View File

@@ -14,14 +14,28 @@
- (CGSize)sizeValueForFrame:(NSNumber *)frame {
CGFloat progress = [self progressForFrame:frame];
CGSize returnSize;
if (progress == 0) {
return self.leadingKeyframe.sizeValue;
returnSize = self.leadingKeyframe.sizeValue;
}else if (progress == 1) {
returnSize = self.trailingKeyframe.sizeValue;
} else {
returnSize = CGSizeMake(LOT_RemapValue(progress, 0, 1, self.leadingKeyframe.sizeValue.width, self.trailingKeyframe.sizeValue.width),
LOT_RemapValue(progress, 0, 1, self.leadingKeyframe.sizeValue.height, self.trailingKeyframe.sizeValue.height));
}
if (progress == 1) {
return self.trailingKeyframe.sizeValue;
if (self.hasValueOverride) {
return self.sizeCallback.callback(self.leadingKeyframe.keyframeTime.floatValue, self.trailingKeyframe.keyframeTime.floatValue, self.leadingKeyframe.sizeValue, self.trailingKeyframe.sizeValue, returnSize, progress, frame.floatValue);
}
return CGSizeMake(LOT_RemapValue(progress, 0, 1, self.leadingKeyframe.sizeValue.width, self.trailingKeyframe.sizeValue.width),
LOT_RemapValue(progress, 0, 1, self.leadingKeyframe.sizeValue.height, self.trailingKeyframe.sizeValue.height));
return returnSize;
}
- (BOOL)hasValueOverride {
return self.sizeCallback != nil;
}
- (void)setValueCallback:(LOTValueCallback *)valueCallback {
NSAssert(([valueCallback isKindOfClass:[LOTSizeValueCallback class]]), @"Size Interpolator set with incorrect callback type. Expected LOTSizeValueCallback");
self.sizeCallback = (LOTSizeValueCallback*)valueCallback;
}
- (id)keyframeDataForValue:(id)value {

View File

@@ -8,6 +8,7 @@
#import <Foundation/Foundation.h>
#import "LOTKeyframe.h"
#import "LOTValueCallback.h"
NS_ASSUME_NONNULL_BEGIN
@@ -16,11 +17,14 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithKeyframes:(NSArray <LOTKeyframe *> *)keyframes;
/// Used to dynamically update keyframe data.
- (BOOL)setValue:(id)value atFrame:(NSNumber *)frame;
- (BOOL)setValue:(id)value atFrame:(NSNumber *)frame __deprecated;
- (id _Nullable)keyframeDataForValue:(id)value;
@property (nonatomic, weak, nullable) LOTKeyframe *leadingKeyframe;
@property (nonatomic, weak, nullable) LOTKeyframe *trailingKeyframe;
@property (nonatomic, readonly) BOOL hasValueOverride;
- (void)setValueCallback:(LOTValueCallback *)valueCallback;
- (BOOL)hasUpdateForFrame:(NSNumber *)frame;
- (CGFloat)progressForFrame:(NSNumber *)frame;

View File

@@ -30,57 +30,10 @@
return nil;
}
// Change keyframe data
- (BOOL)setValue:(id)value atFrame:(NSNumber *)frame {
id data = [self keyframeDataForValue:value];
if (data == nil) {
return NO;
}
if (frame == nil) {
frame = @0;
}
[self updateKeyframeSpanForFrame:frame];
if (frame.floatValue == self.leadingKeyframe.keyframeTime.floatValue) {
// Is leading frame, replace
LOTKeyframe *newKeyframe = [self.leadingKeyframe copyWithData:data];
NSMutableArray *keyframes = [NSMutableArray arrayWithArray:_keyframes];
NSUInteger idx = [keyframes indexOfObject:self.leadingKeyframe];
[keyframes replaceObjectAtIndex:idx withObject:newKeyframe];
self.leadingKeyframe = newKeyframe;
_keyframes = keyframes;
} else if (frame.floatValue == self.trailingKeyframe.keyframeTime.floatValue) {
// Is trailing frame
LOTKeyframe *newKeyframe = [self.trailingKeyframe copyWithData:data];
NSMutableArray *keyframes = [NSMutableArray arrayWithArray:_keyframes];
NSUInteger idx = [keyframes indexOfObject:self.trailingKeyframe];
[keyframes replaceObjectAtIndex:idx withObject:newKeyframe];
self.trailingKeyframe = newKeyframe;
_keyframes = keyframes;
} else {
// Is between leading and trailing. Either can be nil.
// For now added keyframes will default to linear interpolation.
// TODO BW Add smart bezier interpolation
NSMutableDictionary *keyframeDict = [NSMutableDictionary dictionary];
keyframeDict[@"s"] = data;
keyframeDict[@"t"] = frame;
LOTKeyframe *keyframe = [[LOTKeyframe alloc] initWithKeyframe:keyframeDict];
NSMutableArray *newKeyframes = [NSMutableArray arrayWithArray:_keyframes];
if (self.trailingKeyframe == nil ||
self.trailingKeyframe == newKeyframes.lastObject) {
[newKeyframes addObject:keyframe];
} else {
NSInteger idx = [newKeyframes indexOfObject:self.trailingKeyframe];
[newKeyframes insertObject:keyframe atIndex:idx];
}
_keyframes = newKeyframes;
self.leadingKeyframe = nil;
self.trailingKeyframe = nil;
}
return YES;
}
- (BOOL)hasUpdateForFrame:(NSNumber *)frame {
if (self.hasValueOverride) {
return YES;
}
/*
Cases we dont update keyframe
if time is in span and leading keyframe is hold
@@ -212,4 +165,60 @@
return progession;
}
- (void)setValueCallback:(LOTValueCallback *)valueCallback {
NSAssert((NO), @"Interpolator does not support value callbacks");
}
#pragma mark - DEPRECATED
// Change keyframe data
- (BOOL)setValue:(id)value atFrame:(NSNumber *)frame {
id data = [self keyframeDataForValue:value];
if (data == nil) {
return NO;
}
if (frame == nil) {
frame = @0;
}
[self updateKeyframeSpanForFrame:frame];
if (frame.floatValue == self.leadingKeyframe.keyframeTime.floatValue) {
// Is leading frame, replace
LOTKeyframe *newKeyframe = [self.leadingKeyframe copyWithData:data];
NSMutableArray *keyframes = [NSMutableArray arrayWithArray:_keyframes];
NSUInteger idx = [keyframes indexOfObject:self.leadingKeyframe];
[keyframes replaceObjectAtIndex:idx withObject:newKeyframe];
self.leadingKeyframe = newKeyframe;
_keyframes = keyframes;
} else if (frame.floatValue == self.trailingKeyframe.keyframeTime.floatValue) {
// Is trailing frame
LOTKeyframe *newKeyframe = [self.trailingKeyframe copyWithData:data];
NSMutableArray *keyframes = [NSMutableArray arrayWithArray:_keyframes];
NSUInteger idx = [keyframes indexOfObject:self.trailingKeyframe];
[keyframes replaceObjectAtIndex:idx withObject:newKeyframe];
self.trailingKeyframe = newKeyframe;
_keyframes = keyframes;
} else {
// Is between leading and trailing. Either can be nil.
// For now added keyframes will default to linear interpolation.
// TODO BW Add smart bezier interpolation
NSMutableDictionary *keyframeDict = [NSMutableDictionary dictionary];
keyframeDict[@"s"] = data;
keyframeDict[@"t"] = frame;
LOTKeyframe *keyframe = [[LOTKeyframe alloc] initWithKeyframe:keyframeDict];
NSMutableArray *newKeyframes = [NSMutableArray arrayWithArray:_keyframes];
if (self.trailingKeyframe == nil ||
self.trailingKeyframe == newKeyframes.lastObject) {
[newKeyframes addObject:keyframe];
} else {
NSInteger idx = [newKeyframes indexOfObject:self.trailingKeyframe];
[newKeyframes insertObject:keyframe atIndex:idx];
}
_keyframes = newKeyframes;
self.leadingKeyframe = nil;
self.trailingKeyframe = nil;
}
return YES;
}
@end

View File

@@ -9,6 +9,8 @@
#import <Foundation/Foundation.h>
#import "LOTPlatformCompat.h"
#import "LOTBezierPath.h"
#import "LOTKeypath.h"
#import "LOTValueCallback.h"
extern NSInteger indentation_level;
@interface LOTAnimatorNode : NSObject
@@ -51,18 +53,27 @@ extern NSInteger indentation_level;
/// Rebuild all outputs for the node. This is called after upstream updates have been performed.
- (void)rebuildOutputs;
- (void)logString:(NSString *_Nonnull)string;
- (void)searchNodesForKeypath:(LOTKeypath * _Nonnull)keypath;
- (void)setValueCallback:(nonnull LOTValueCallback *)callbackBlock
forKeypath:(nonnull LOTKeypath *)keypath;
/*
* DEPRECATED
*/
/// Traverses children untill keypath is found and attempts to set the keypath to the value.
- (BOOL)setValue:(nonnull id)value
forKeyAtPath:(nonnull NSString *)keypath
forFrame:(nullable NSNumber *)frame;
forFrame:(nullable NSNumber *)frame __deprecated;
/// Sets the keyframe to the value, to be overwritten by subclasses
- (BOOL)setInterpolatorValue:(nonnull id)value
forKey:(nonnull NSString *)key
forFrame:(nullable NSNumber *)frame;
forFrame:(nullable NSNumber *)frame __deprecated;
- (void)logString:(NSString *_Nonnull)string;
- (void)logHierarchyKeypathsWithParent:(NSString * _Nullable)parent;
- (void)logHierarchyKeypathsWithParent:(NSString * _Nullable)parent __deprecated;
@end

View File

@@ -14,7 +14,6 @@ NSInteger indentation_level = 0;
@implementation LOTAnimatorNode
- (instancetype _Nonnull)initWithInputNode:(LOTAnimatorNode *_Nullable)inputNode
keyName:(NSString *_Nullable)keyname {
self = [super init];
@@ -98,6 +97,39 @@ NSInteger indentation_level = 0;
self.inputNode.pathShouldCacheLengths = pathShouldCacheLengths;
}
- (void)searchNodesForKeypath:(LOTKeypath * _Nonnull)keypath {
[self.inputNode searchNodesForKeypath:keypath];
if ([keypath pushKey:self.keyname]) {
// Matches self. Check interpolators
if (keypath.endOfKeypath) {
// Add self
[keypath addSearchResultForCurrentPath:self];
} else if (self.valueInterpolators[keypath.currentKey] != nil) {
[keypath pushKey:keypath.currentKey];
// We have a match!
[keypath addSearchResultForCurrentPath:self];
[keypath popKey];
}
[keypath popKey];
}
}
- (void)setValueCallback:(nonnull LOTValueCallback *)callbackBlock
forKeypath:(nonnull LOTKeypath *)keypath {
if ([keypath pushKey:self.keyname]) {
// Matches self. Check interpolators
LOTValueInterpolator *interpolator = self.valueInterpolators[keypath.currentKey];
if (interpolator) {
// We have a match!
[interpolator setValueCallback:callbackBlock];
}
[keypath popKey];
}
[self.inputNode setValueCallback:callbackBlock forKeypath:keypath];
}
#pragma mark - DEPRECATED
/// Traverses children untill keypath is found and attempts to set the keypath to the value.
- (BOOL)setValue:(nonnull id)value
forKeyAtPath:(nonnull NSString *)keypath

View File

@@ -48,11 +48,18 @@
- (NSDictionary *)valueInterpolators {
if (_opacityInterpolator && _transformInterolator) {
return @{@"Transform.Opacity" : _opacityInterpolator,
return @{@"Opacity" : _opacityInterpolator,
@"Position" : _transformInterolator.positionInterpolator,
@"Scale" : _transformInterolator.scaleInterpolator,
@"Rotation" : _transformInterolator.scaleInterpolator,
@"Anchor Point" : _transformInterolator.anchorInterpolator,
// Deprecated
@"Transform.Opacity" : _opacityInterpolator,
@"Transform.Position" : _transformInterolator.positionInterpolator,
@"Transform.Scale" : _transformInterolator.scaleInterpolator,
@"Transform.Rotation" : _transformInterolator.scaleInterpolator,
@"Transform.Anchor Point" : _transformInterolator.anchorInterpolator};
@"Transform.Anchor Point" : _transformInterolator.anchorInterpolator
};
}
return nil;
}
@@ -176,6 +183,59 @@
return _outputPath;
}
- (void)searchNodesForKeypath:(LOTKeypath * _Nonnull)keypath {
[self.inputNode searchNodesForKeypath:keypath];
if ([keypath pushKey:self.keyname]) {
// Matches self. Dig deeper.
// Check interpolators
if ([keypath pushKey:@"Transform"]) {
// Matches a Transform interpolator!
if (self.valueInterpolators[keypath.currentKey] != nil) {
[keypath pushKey:keypath.currentKey];
[keypath addSearchResultForCurrentPath:self];
[keypath popKey];
}
[keypath popKey];
}
if (keypath.endOfKeypath) {
// We have a match!
[keypath addSearchResultForCurrentPath:self];
}
// Check child nodes
[_rootNode searchNodesForKeypath:keypath];
[keypath popKey];
}
}
- (void)setValueCallback:(nonnull LOTValueCallback *)callbackBlock
forKeypath:(nonnull LOTKeypath *)keypath {
if ([keypath pushKey:self.keyname]) {
// Matches self. Dig deeper.
// Check interpolators
if ([keypath pushKey:@"Transform"]) {
// Matches a Transform interpolator!
LOTValueInterpolator *interpolator = self.valueInterpolators[keypath.currentKey];
if (interpolator) {
// We have a match!
[interpolator setValueCallback:callbackBlock];
}
[keypath popKey];
}
// Check child nodes
[_rootNode setValueCallback:callbackBlock forKeypath:keypath];
[keypath popKey];
}
// Check upstream
[self.inputNode setValueCallback:callbackBlock forKeypath:keypath];
}
#pragma mark - DEPRECATED
- (BOOL)setInterpolatorValue:(id)value
forKey:(NSString *)key
forFrame:(NSNumber *)frame {