Native Animated - Add tests on iOS
Summary: Adds unit tests to the Native Animated implementation on iOS. This pretty much mirrors the tests we currently have on Android. It also fixes 2 bugs I've found when adding the tests and pass the current time in `stepAnimation` instead of using `CACurrentMediaTime` to make testing easier. - `stopListeningToAnimatedNodeValue` did not actually work at all, it should set the listener to nil. - The finished value in the animation end callback was always true, this simplifies the `RCTAnimationDriver` interface to get rid of `removeAnimation` and fixes the end callback value. **Test plan** - Run the tests - Make sure the UIExplorer example still works Closes https://github.com/facebook/react-native/pull/13068 Differential Revision: D4786701 Pulled By: javache fbshipit-source-id: a4f07e6eec1f363ca47b6f27984041793c915bfc
This commit is contained in:
parent
fb54a1eb3e
commit
1d37dd063c
|
@ -55,6 +55,10 @@
|
|||
14D6D7281B2222EF001FB087 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDED91B0651EA00C62182 /* libRCTWebSocket.a */; };
|
||||
14D6D7291B2222EF001FB087 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14AADF041AC3DB95002390C9 /* libReact.a */; };
|
||||
14DC67F41AB71881001358AB /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14DC67F11AB71876001358AB /* libRCTPushNotification.a */; };
|
||||
192F69B81E82409A008692C7 /* RCTAnimationUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 192F69B51E82409A008692C7 /* RCTAnimationUtilsTests.m */; };
|
||||
192F69B91E82409A008692C7 /* RCTConvert_YGValueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 192F69B61E82409A008692C7 /* RCTConvert_YGValueTests.m */; };
|
||||
192F69BA1E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 192F69B71E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m */; };
|
||||
192F69DA1E8240E2008692C7 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13E501A31D07A502005F35D8 /* libRCTAnimation.a */; };
|
||||
272E6B3F1BEA849E001FCF37 /* UpdatePropertiesExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */; };
|
||||
27B885561BED29AF00008352 /* RCTRootViewIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */; };
|
||||
27F441EC1BEBE5030039B79C /* FlexibleSizeExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */; };
|
||||
|
@ -422,6 +426,9 @@
|
|||
14D6D7101B220EB3001FB087 /* libOCMock.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libOCMock.a; sourceTree = "<group>"; };
|
||||
14DC67E71AB71876001358AB /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = ../../Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj; sourceTree = "<group>"; };
|
||||
14E0EEC81AB118F7000DECC3 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../../Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = "<group>"; };
|
||||
192F69B51E82409A008692C7 /* RCTAnimationUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAnimationUtilsTests.m; sourceTree = "<group>"; };
|
||||
192F69B61E82409A008692C7 /* RCTConvert_YGValueTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert_YGValueTests.m; sourceTree = "<group>"; };
|
||||
192F69B71E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTNativeAnimatedNodesManagerTests.m; sourceTree = "<group>"; };
|
||||
272E6B3B1BEA849E001FCF37 /* UpdatePropertiesExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UpdatePropertiesExampleView.h; path = UIExplorer/NativeExampleViews/UpdatePropertiesExampleView.h; sourceTree = "<group>"; };
|
||||
272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UpdatePropertiesExampleView.m; path = UIExplorer/NativeExampleViews/UpdatePropertiesExampleView.m; sourceTree = "<group>"; };
|
||||
27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootViewIntegrationTests.m; sourceTree = "<group>"; };
|
||||
|
@ -456,6 +463,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
192F69DA1E8240E2008692C7 /* libRCTAnimation.a in Frameworks */,
|
||||
14D6D71E1B2222EF001FB087 /* libRCTActionSheet.a in Frameworks */,
|
||||
14D6D71F1B2222EF001FB087 /* libRCTAdSupport.a in Frameworks */,
|
||||
14D6D7201B2222EF001FB087 /* libRCTGeolocation.a in Frameworks */,
|
||||
|
@ -660,6 +668,9 @@
|
|||
143BC57C1B21E18100462512 /* UIExplorerUnitTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
192F69B51E82409A008692C7 /* RCTAnimationUtilsTests.m */,
|
||||
192F69B61E82409A008692C7 /* RCTConvert_YGValueTests.m */,
|
||||
192F69B71E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m */,
|
||||
13B6C1A21C34225900D3FAF5 /* RCTURLUtilsTests.m */,
|
||||
68FF44371CF6111500720EFD /* RCTBundleURLProviderTests.m */,
|
||||
1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */,
|
||||
|
@ -1433,8 +1444,10 @@
|
|||
1497CFAF1B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m in Sources */,
|
||||
1497CFAE1B21F5E400C1F8F2 /* RCTJSCExecutorTests.m in Sources */,
|
||||
13129DD41C85F87C007D611C /* RCTModuleInitNotificationRaceTests.m in Sources */,
|
||||
192F69B81E82409A008692C7 /* RCTAnimationUtilsTests.m in Sources */,
|
||||
1497CFAD1B21F5E400C1F8F2 /* RCTBridgeTests.m in Sources */,
|
||||
134CB92A1C85A38800265FA6 /* RCTModuleInitTests.m in Sources */,
|
||||
192F69BA1E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m in Sources */,
|
||||
1497CFB11B21F5E400C1F8F2 /* RCTEventDispatcherTests.m in Sources */,
|
||||
1497CFB31B21F5E400C1F8F2 /* RCTUIManagerTests.m in Sources */,
|
||||
13DB03481B5D2ED500C27245 /* RCTJSONTests.m in Sources */,
|
||||
|
@ -1445,6 +1458,7 @@
|
|||
39AA31A41DC1DFDC000F7EBB /* RCTUnicodeDecodeTests.m in Sources */,
|
||||
13B6C1A31C34225900D3FAF5 /* RCTURLUtilsTests.m in Sources */,
|
||||
8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */,
|
||||
192F69B91E82409A008692C7 /* RCTConvert_YGValueTests.m in Sources */,
|
||||
BC9C03401DC9F1D600B1C635 /* RCTDevMenuTests.m in Sources */,
|
||||
68FF44381CF6111500720EFD /* RCTBundleURLProviderTests.m in Sources */,
|
||||
8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.m in Sources */,
|
||||
|
@ -1613,9 +1627,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
|
||||
INFOPLIST_FILE = "$(SRCROOT)/UIExplorer/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.react.uiapp;
|
||||
PRODUCT_NAME = UIExplorer;
|
||||
|
@ -1629,7 +1641,6 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
DEVELOPMENT_TEAM = V9WTTPBFK9;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/UIExplorer/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.react.uiapp;
|
||||
PRODUCT_NAME = UIExplorer;
|
||||
|
@ -1864,6 +1875,7 @@
|
|||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
|
@ -1907,9 +1919,7 @@
|
|||
WARNING_CFLAGS = (
|
||||
"-Wextra",
|
||||
"-Wall",
|
||||
"-Wincompatible-pointer-types",
|
||||
"-Wincompatible-pointer-types-discards-qualifiers",
|
||||
"-Wshadow",
|
||||
"-Wno-semicolon-before-method-body",
|
||||
);
|
||||
};
|
||||
name = Debug;
|
||||
|
@ -1933,6 +1943,7 @@
|
|||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
|
@ -1969,9 +1980,7 @@
|
|||
WARNING_CFLAGS = (
|
||||
"-Wextra",
|
||||
"-Wall",
|
||||
"-Wincompatible-pointer-types",
|
||||
"-Wincompatible-pointer-types-discards-qualifiers",
|
||||
"-Wshadow",
|
||||
"-Wno-semicolon-before-method-body",
|
||||
);
|
||||
};
|
||||
name = Release;
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import <RCTAnimation/RCTAnimationUtils.h>
|
||||
|
||||
@interface RCTAnimationUtilsTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
static CGFloat RCTSimpleInterpolation(CGFloat value, NSArray<NSNumber *> *inputRange, NSArray<NSNumber *> *outputRange) {
|
||||
return RCTInterpolateValueInRange(value,
|
||||
inputRange,
|
||||
outputRange,
|
||||
EXTRAPOLATE_TYPE_EXTEND,
|
||||
EXTRAPOLATE_TYPE_EXTEND);
|
||||
}
|
||||
|
||||
@implementation RCTAnimationUtilsTests
|
||||
|
||||
// RCTInterpolateValueInRange
|
||||
|
||||
- (void)testSimpleOneToOneMapping
|
||||
{
|
||||
NSArray<NSNumber *> *input = @[@0, @1];
|
||||
NSArray<NSNumber *> *output = @[@0, @1];
|
||||
XCTAssertEqual(RCTSimpleInterpolation(0, input, output), 0);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(0.5, input, output), 0.5);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(0.8, input, output), 0.8);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(1, input, output), 1);
|
||||
}
|
||||
|
||||
- (void)testWiderOutputRange
|
||||
{
|
||||
NSArray<NSNumber *> *input = @[@0, @1];
|
||||
NSArray<NSNumber *> *output = @[@100, @200];
|
||||
XCTAssertEqual(RCTSimpleInterpolation(0, input, output), 100);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(0.5, input, output), 150);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(0.8, input, output), 180);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(1, input, output), 200);
|
||||
}
|
||||
|
||||
- (void)testWiderInputRange
|
||||
{
|
||||
NSArray<NSNumber *> *input = @[@2000, @3000];
|
||||
NSArray<NSNumber *> *output = @[@1, @2];
|
||||
XCTAssertEqual(RCTSimpleInterpolation(2000, input, output), 1);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(2250, input, output), 1.25);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(2800, input, output), 1.8);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(3000, input, output), 2);
|
||||
}
|
||||
|
||||
- (void)testManySegments
|
||||
{
|
||||
NSArray<NSNumber *> *input = @[@-1, @1, @5];
|
||||
NSArray<NSNumber *> *output = @[@0, @10, @20];
|
||||
XCTAssertEqual(RCTSimpleInterpolation(-1, input, output), 0);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(0, input, output), 5);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(1, input, output), 10);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(2, input, output), 12.5);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(5, input, output), 20);
|
||||
}
|
||||
|
||||
- (void)testExtendExtrapolate
|
||||
{
|
||||
NSArray<NSNumber *> *input = @[@10, @20];
|
||||
NSArray<NSNumber *> *output = @[@0, @1];
|
||||
XCTAssertEqual(RCTSimpleInterpolation(30, input, output), 2);
|
||||
XCTAssertEqual(RCTSimpleInterpolation(5, input, output), -0.5);
|
||||
}
|
||||
|
||||
- (void)testClampExtrapolate
|
||||
{
|
||||
NSArray<NSNumber *> *input = @[@10, @20];
|
||||
NSArray<NSNumber *> *output = @[@0, @1];
|
||||
CGFloat value;
|
||||
value = RCTInterpolateValueInRange(30,
|
||||
input,
|
||||
output,
|
||||
EXTRAPOLATE_TYPE_CLAMP,
|
||||
EXTRAPOLATE_TYPE_CLAMP);
|
||||
XCTAssertEqual(value, 1);
|
||||
value = RCTInterpolateValueInRange(5,
|
||||
input,
|
||||
output,
|
||||
EXTRAPOLATE_TYPE_CLAMP,
|
||||
EXTRAPOLATE_TYPE_CLAMP);
|
||||
XCTAssertEqual(value, 0);
|
||||
}
|
||||
|
||||
- (void)testIdentityExtrapolate
|
||||
{
|
||||
NSArray<NSNumber *> *input = @[@10, @20];
|
||||
NSArray<NSNumber *> *output = @[@0, @1];
|
||||
CGFloat value;
|
||||
value = RCTInterpolateValueInRange(30,
|
||||
input,
|
||||
output,
|
||||
EXTRAPOLATE_TYPE_IDENTITY,
|
||||
EXTRAPOLATE_TYPE_IDENTITY);
|
||||
XCTAssertEqual(value, 30);
|
||||
value = RCTInterpolateValueInRange(5,
|
||||
input,
|
||||
output,
|
||||
EXTRAPOLATE_TYPE_IDENTITY,
|
||||
EXTRAPOLATE_TYPE_IDENTITY);
|
||||
XCTAssertEqual(value, 5);
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,666 @@
|
|||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import <OCMock/OCMock.h>
|
||||
|
||||
#import <RCTAnimation/RCTNativeAnimatedNodesManager.h>
|
||||
#import <RCTAnimation/RCTValueAnimatedNode.h>
|
||||
#import <React/RCTUIManager.h>
|
||||
|
||||
static const NSTimeInterval FRAME_LENGTH = 1.0 / 60.0;
|
||||
|
||||
@interface RCTFakeDisplayLink : CADisplayLink
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTFakeDisplayLink
|
||||
{
|
||||
NSTimeInterval _timestamp;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_timestamp = 1124.1234143251; // Random
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSTimeInterval)timestamp
|
||||
{
|
||||
_timestamp += FRAME_LENGTH;
|
||||
return _timestamp;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTFakeValueObserver : NSObject<RCTValueAnimatedNodeObserver>
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray<NSNumber *> *calls;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTFakeValueObserver
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_calls = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)animatedNode:(__unused RCTValueAnimatedNode *)node didUpdateValue:(CGFloat)value
|
||||
{
|
||||
[_calls addObject:@(value)];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTFakeEvent : NSObject<RCTEvent>
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTFakeEvent
|
||||
{
|
||||
NSArray *_arguments;
|
||||
}
|
||||
|
||||
@synthesize eventName = _eventName;
|
||||
@synthesize viewTag = _viewTag;
|
||||
@synthesize coalescingKey = _coalescingKey;
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name viewTag:(NSNumber *)viewTag arguments:(NSArray *)arguments
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_eventName = name;
|
||||
_viewTag = viewTag;
|
||||
_arguments = arguments;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray *)arguments
|
||||
{
|
||||
return _arguments;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(+ (NSString *)moduleDotMethod);
|
||||
RCT_NOT_IMPLEMENTED(- (BOOL)canCoalesce);
|
||||
RCT_NOT_IMPLEMENTED(- (id<RCTEvent>)coalesceWithEvent:(id<RCTEvent>)newEvent);
|
||||
|
||||
@end
|
||||
|
||||
static id RCTPropChecker(NSString *prop, NSNumber *value)
|
||||
{
|
||||
return [OCMArg checkWithBlock:^BOOL(NSDictionary<NSString *, NSNumber *> *props) {
|
||||
BOOL match = fabs(props[prop].doubleValue - value.doubleValue) < FLT_EPSILON;
|
||||
if (!match) {
|
||||
NSLog(@"Props `%@` with value `%@` is not close to `%@`", prop, props[prop], value);
|
||||
}
|
||||
return match;
|
||||
}];
|
||||
}
|
||||
|
||||
@interface RCTNativeAnimatedNodesManagerTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTNativeAnimatedNodesManagerTests
|
||||
{
|
||||
id _uiManager;
|
||||
RCTNativeAnimatedNodesManager *_nodesManager;
|
||||
RCTFakeDisplayLink *_displayLink;
|
||||
}
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
|
||||
_uiManager = [OCMockObject niceMockForClass:[RCTUIManager class]];
|
||||
_nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithUIManager:_uiManager];
|
||||
_displayLink = [RCTFakeDisplayLink new];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a simple animated nodes graph and attaches the props node to a given viewTag
|
||||
* Parameter opacity is used as a initial value for the "opacity" attribute.
|
||||
*
|
||||
* Nodes are connected as follows (nodes IDs in parens):
|
||||
* ValueNode(1) -> StyleNode(2) -> PropNode(3)
|
||||
*/
|
||||
- (void)createSimpleAnimatedView:(NSNumber *)viewTag withOpacity:(CGFloat)opacity
|
||||
{
|
||||
[_nodesManager createAnimatedNode:@1
|
||||
config:@{@"type": @"value", @"value": @(opacity), @"offset": @0}];
|
||||
[_nodesManager createAnimatedNode:@2
|
||||
config:@{@"type": @"style", @"style": @{@"opacity": @1}}];
|
||||
[_nodesManager createAnimatedNode:@3
|
||||
config:@{@"type": @"props", @"props": @{@"style": @2}}];
|
||||
|
||||
[_nodesManager connectAnimatedNodes:@1 childTag:@2];
|
||||
[_nodesManager connectAnimatedNodes:@2 childTag:@3];
|
||||
[_nodesManager connectAnimatedNodeToView:@3 viewTag:viewTag viewName:@"UIView"];
|
||||
}
|
||||
|
||||
- (void)testFramesAnimation
|
||||
{
|
||||
[self createSimpleAnimatedView:@1000 withOpacity:0];
|
||||
NSArray<NSNumber *> *frames = @[@0, @0.2, @0.4, @0.6, @0.8, @1];
|
||||
[_nodesManager startAnimatingNode:@1
|
||||
nodeTag:@1
|
||||
config:@{@"type": @"frames", @"frames": frames, @"toValue": @1}
|
||||
endCallback:nil];
|
||||
|
||||
for (NSNumber *frame in frames) {
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:@1000
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"opacity", frame)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
}
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:@1000
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"opacity", @1)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
[[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
}
|
||||
|
||||
- (void)testNodeValueListenerIfNotListening
|
||||
{
|
||||
NSNumber *nodeId = @1;
|
||||
[self createSimpleAnimatedView:@1000 withOpacity:0];
|
||||
NSArray<NSNumber *> *frames = @[@0, @0.2, @0.4, @0.6, @0.8, @1];
|
||||
|
||||
RCTFakeValueObserver *observer = [RCTFakeValueObserver new];
|
||||
[_nodesManager startListeningToAnimatedNodeValue:nodeId valueObserver:observer];
|
||||
|
||||
[_nodesManager startAnimatingNode:@1
|
||||
nodeTag:nodeId
|
||||
config:@{@"type": @"frames", @"frames": frames, @"toValue": @1}
|
||||
endCallback:nil];
|
||||
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
XCTAssertEqual(observer.calls.count, 1UL);
|
||||
XCTAssertEqualObjects(observer.calls[0], @0);
|
||||
|
||||
[_nodesManager stopListeningToAnimatedNodeValue:nodeId];
|
||||
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
XCTAssertEqual(observer.calls.count, 1UL);
|
||||
}
|
||||
|
||||
- (void)testNodeValueListenerIfListening
|
||||
{
|
||||
NSNumber *nodeId = @1;
|
||||
[self createSimpleAnimatedView:@1000 withOpacity:0];
|
||||
NSArray<NSNumber *> *frames = @[@0, @0.2, @0.4, @0.6, @0.8, @1];
|
||||
|
||||
RCTFakeValueObserver *observer = [RCTFakeValueObserver new];
|
||||
[_nodesManager startListeningToAnimatedNodeValue:nodeId valueObserver:observer];
|
||||
|
||||
[_nodesManager startAnimatingNode:@1
|
||||
nodeTag:nodeId
|
||||
config:@{@"type": @"frames", @"frames": frames, @"toValue": @1}
|
||||
endCallback:nil];
|
||||
|
||||
for (NSUInteger i = 0; i < frames.count; i++) {
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
XCTAssertEqual(observer.calls.count, i + 1);
|
||||
XCTAssertEqualWithAccuracy(observer.calls[i].doubleValue, frames[i].doubleValue, FLT_EPSILON);
|
||||
}
|
||||
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
XCTAssertEqual(observer.calls.count, 7UL);
|
||||
XCTAssertEqualObjects(observer.calls[6], @1);
|
||||
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
XCTAssertEqual(observer.calls.count, 7UL);
|
||||
}
|
||||
|
||||
- (void)testSpringAnimation
|
||||
{
|
||||
[self createSimpleAnimatedView:@1000 withOpacity:0];
|
||||
[_nodesManager startAnimatingNode:@1
|
||||
nodeTag:@1
|
||||
config:@{@"type": @"spring",
|
||||
@"friction": @7,
|
||||
@"tension": @40,
|
||||
@"initialVelocity": @0,
|
||||
@"toValue": @1,
|
||||
@"restSpeedThreshold": @0.001,
|
||||
@"restDisplacementThreshold": @0.001,
|
||||
@"overshootClamping": @NO}
|
||||
endCallback:nil];
|
||||
|
||||
BOOL wasGreaterThanOne = NO;
|
||||
CGFloat previousValue = 0;
|
||||
__block CGFloat currentValue;
|
||||
[[[_uiManager stub] andDo:^(NSInvocation *invocation) {
|
||||
__unsafe_unretained NSDictionary<NSString *, NSNumber *> *props;
|
||||
[invocation getArgument:&props atIndex:4];
|
||||
currentValue = props[@"opacity"].doubleValue;
|
||||
}] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
|
||||
// Run for 3 seconds.
|
||||
for (NSUInteger i = 0; i < 3 * 60; i++) {
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
|
||||
if (currentValue > 1) {
|
||||
wasGreaterThanOne = YES;
|
||||
}
|
||||
|
||||
// Verify that animation step is relatively small.
|
||||
XCTAssertLessThan(fabs(currentValue - previousValue), 0.1);
|
||||
|
||||
previousValue = currentValue;
|
||||
}
|
||||
|
||||
// Verify that we've reach the final value at the end of animation.
|
||||
XCTAssertEqual(previousValue, 1.0);
|
||||
|
||||
// Verify that value has reached some maximum value that is greater than the final value (bounce).
|
||||
XCTAssertTrue(wasGreaterThanOne);
|
||||
|
||||
[[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
}
|
||||
|
||||
- (void)testAnimationCallbackFinish
|
||||
{
|
||||
[self createSimpleAnimatedView:@1000 withOpacity:0];
|
||||
NSArray<NSNumber *> *frames = @[@0, @1];
|
||||
|
||||
__block NSInteger endCallbackCalls = 0;
|
||||
|
||||
RCTResponseSenderBlock endCallback = ^(NSArray *response) {
|
||||
endCallbackCalls++;
|
||||
XCTAssertEqualObjects(response, @[@{@"finished": @YES}]);
|
||||
};
|
||||
|
||||
[_nodesManager startAnimatingNode:@1
|
||||
nodeTag:@1
|
||||
config:@{@"type": @"frames", @"frames": frames, @"toValue": @1}
|
||||
endCallback:endCallback];
|
||||
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
XCTAssertEqual(endCallbackCalls, 0);
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
XCTAssertEqual(endCallbackCalls, 1);
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
XCTAssertEqual(endCallbackCalls, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a following graph of nodes:
|
||||
* Value(1, firstValue) ----> Add(3) ---> Style(4) ---> Props(5) ---> View(viewTag)
|
||||
* |
|
||||
* Value(2, secondValue) --+
|
||||
*
|
||||
* Add(3) node maps to a "translateX" attribute of the Style(4) node.
|
||||
*/
|
||||
- (void)createAnimatedGraphWithAdditionNode:(NSNumber *)viewTag
|
||||
firstValue:(CGFloat)firstValue
|
||||
secondValue:(CGFloat)secondValue
|
||||
{
|
||||
[_nodesManager createAnimatedNode:@1
|
||||
config:@{@"type": @"value", @"value": @(firstValue), @"offset": @0}];
|
||||
[_nodesManager createAnimatedNode:@2
|
||||
config:@{@"type": @"value", @"value": @(secondValue), @"offset": @0}];
|
||||
[_nodesManager createAnimatedNode:@3
|
||||
config:@{@"type": @"addition", @"input": @[@1, @2]}];
|
||||
[_nodesManager createAnimatedNode:@4
|
||||
config:@{@"type": @"style", @"style": @{@"translateX": @3}}];
|
||||
[_nodesManager createAnimatedNode:@5
|
||||
config:@{@"type": @"props", @"props": @{@"style": @4}}];
|
||||
|
||||
[_nodesManager connectAnimatedNodes:@1 childTag:@3];
|
||||
[_nodesManager connectAnimatedNodes:@2 childTag:@3];
|
||||
[_nodesManager connectAnimatedNodes:@3 childTag:@4];
|
||||
[_nodesManager connectAnimatedNodes:@4 childTag:@5];
|
||||
[_nodesManager connectAnimatedNodeToView:@5 viewTag:viewTag viewName:@"UIView"];
|
||||
}
|
||||
|
||||
- (void)testAdditionNode
|
||||
{
|
||||
NSNumber *viewTag = @50;
|
||||
[self createAnimatedGraphWithAdditionNode:viewTag firstValue:100 secondValue:1000];
|
||||
|
||||
NSArray<NSNumber *> *frames = @[@0, @1];
|
||||
[_nodesManager startAnimatingNode:@1
|
||||
nodeTag:@1
|
||||
config:@{@"type": @"frames", @"frames": frames, @"toValue": @101}
|
||||
endCallback:nil];
|
||||
[_nodesManager startAnimatingNode:@2
|
||||
nodeTag:@2
|
||||
config:@{@"type": @"frames", @"frames": frames, @"toValue": @1010}
|
||||
endCallback:nil];
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"translateX", @1100)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"translateX", @1111)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"translateX", @1111)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
[[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that views are updated properly when one of the addition input nodes has started animating
|
||||
* while the other one has not.
|
||||
*
|
||||
* We expect that the output of the addition node will take the starting value of the second input
|
||||
* node even though the node hasn't been connected to an active animation driver.
|
||||
*/
|
||||
- (void)testViewReceiveUpdatesIfOneOfAnimationHasntStarted
|
||||
{
|
||||
NSNumber *viewTag = @50;
|
||||
[self createAnimatedGraphWithAdditionNode:viewTag firstValue:100 secondValue:1000];
|
||||
|
||||
NSArray<NSNumber *> *frames = @[@0, @1];
|
||||
[_nodesManager startAnimatingNode:@1
|
||||
nodeTag:@1
|
||||
config:@{@"type": @"frames", @"frames": frames, @"toValue": @101}
|
||||
endCallback:nil];
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"translateX", @1100)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"translateX", @1101)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"translateX", @1101)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
[[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that views are updated properly when one of the addition input nodes animation finishes
|
||||
* before the other.
|
||||
*
|
||||
* We expect that the output of the addition node after one of the animation has finished will
|
||||
* take the last value of the animated node and the view will receive updates up until the second
|
||||
* animation is over.
|
||||
*/
|
||||
- (void)testViewReceiveUpdatesWhenOneOfAnimationHasFinished
|
||||
{
|
||||
NSNumber *viewTag = @50;
|
||||
[self createAnimatedGraphWithAdditionNode:viewTag firstValue:100 secondValue:1000];
|
||||
|
||||
NSArray<NSNumber *> *firstFrames = @[@0, @1];
|
||||
[_nodesManager startAnimatingNode:@1
|
||||
nodeTag:@1
|
||||
config:@{@"type": @"frames", @"frames": firstFrames, @"toValue": @200}
|
||||
endCallback:nil];
|
||||
NSArray<NSNumber *> *secondFrames = @[@0, @0.2, @0.4, @0.6, @0.8, @1];
|
||||
[_nodesManager startAnimatingNode:@2
|
||||
nodeTag:@2
|
||||
config:@{@"type": @"frames", @"frames": secondFrames, @"toValue": @1010}
|
||||
endCallback:nil];
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"translateX", @1100)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
for (NSUInteger i = 1; i < secondFrames.count; i++) {
|
||||
CGFloat expected = 1200.0 + secondFrames[i].doubleValue * 10.0;
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"translateX", @(expected))];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
}
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"translateX", @1210)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
[[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
}
|
||||
|
||||
- (void)testMultiplicationNode
|
||||
{
|
||||
NSNumber *viewTag = @50;
|
||||
[_nodesManager createAnimatedNode:@1
|
||||
config:@{@"type": @"value", @"value": @1, @"offset": @0}];
|
||||
[_nodesManager createAnimatedNode:@2
|
||||
config:@{@"type": @"value", @"value": @5, @"offset": @0}];
|
||||
[_nodesManager createAnimatedNode:@3
|
||||
config:@{@"type": @"multiplication", @"input": @[@1, @2]}];
|
||||
[_nodesManager createAnimatedNode:@4
|
||||
config:@{@"type": @"style", @"style": @{@"translateX": @3}}];
|
||||
[_nodesManager createAnimatedNode:@5
|
||||
config:@{@"type": @"props", @"props": @{@"style": @4}}];
|
||||
|
||||
[_nodesManager connectAnimatedNodes:@1 childTag:@3];
|
||||
[_nodesManager connectAnimatedNodes:@2 childTag:@3];
|
||||
[_nodesManager connectAnimatedNodes:@3 childTag:@4];
|
||||
[_nodesManager connectAnimatedNodes:@4 childTag:@5];
|
||||
[_nodesManager connectAnimatedNodeToView:@5 viewTag:viewTag viewName:@"UIView"];
|
||||
|
||||
NSArray<NSNumber *> *frames = @[@0, @1];
|
||||
[_nodesManager startAnimatingNode:@1
|
||||
nodeTag:@1
|
||||
config:@{@"type": @"frames", @"frames": frames, @"toValue": @2}
|
||||
endCallback:nil];
|
||||
[_nodesManager startAnimatingNode:@2
|
||||
nodeTag:@2
|
||||
config:@{@"type": @"frames", @"frames": frames, @"toValue": @10}
|
||||
endCallback:nil];
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"translateX", @5)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"translateX", @20)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"translateX", @20)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
[[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
}
|
||||
|
||||
- (void)testHandleStoppingAnimation
|
||||
{
|
||||
[self createSimpleAnimatedView:@1000 withOpacity:0];
|
||||
NSArray<NSNumber *> *frames = @[@0, @0.2, @0.4, @0.6, @0.8, @1];
|
||||
|
||||
__block BOOL endCallbackCalled = NO;
|
||||
|
||||
RCTResponseSenderBlock endCallback = ^(NSArray *response) {
|
||||
endCallbackCalled = YES;
|
||||
XCTAssertEqualObjects(response, @[@{@"finished": @NO}]);
|
||||
};
|
||||
|
||||
[_nodesManager startAnimatingNode:@404
|
||||
nodeTag:@1
|
||||
config:@{@"type": @"frames", @"frames": frames, @"toValue": @1}
|
||||
endCallback:endCallback];
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
[_nodesManager stopAnimation:@404];
|
||||
XCTAssertEqual(endCallbackCalled, YES);
|
||||
|
||||
// Run "update" loop a few more times -> we expect no further updates nor callback calls to be
|
||||
// triggered
|
||||
for (NSUInteger i = 0; i < 5; i++) {
|
||||
[[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testInterpolationNode
|
||||
{
|
||||
NSNumber *viewTag = @50;
|
||||
[_nodesManager createAnimatedNode:@1
|
||||
config:@{@"type": @"value", @"value": @10, @"offset": @0}];
|
||||
[_nodesManager createAnimatedNode:@2
|
||||
config:@{@"type": @"interpolation",
|
||||
@"inputRange": @[@10, @20],
|
||||
@"outputRange": @[@0, @1],
|
||||
@"extrapolateLeft": @"extend",
|
||||
@"extrapolateRight": @"extend"}];
|
||||
[_nodesManager createAnimatedNode:@3
|
||||
config:@{@"type": @"style", @"style": @{@"opacity": @2}}];
|
||||
[_nodesManager createAnimatedNode:@4
|
||||
config:@{@"type": @"props", @"props": @{@"style": @3}}];
|
||||
|
||||
[_nodesManager connectAnimatedNodes:@1 childTag:@2];
|
||||
[_nodesManager connectAnimatedNodes:@2 childTag:@3];
|
||||
[_nodesManager connectAnimatedNodes:@3 childTag:@4];
|
||||
[_nodesManager connectAnimatedNodeToView:@4 viewTag:viewTag viewName:@"UIView"];
|
||||
|
||||
NSArray<NSNumber *> *frames = @[@0, @0.2, @0.4, @0.6, @0.8, @1];
|
||||
[_nodesManager startAnimatingNode:@1
|
||||
nodeTag:@1
|
||||
config:@{@"type": @"frames", @"frames": frames, @"toValue": @20}
|
||||
endCallback:nil];
|
||||
|
||||
for (NSNumber *frame in frames) {
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"opacity", frame)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
}
|
||||
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"opacity", @1)];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
|
||||
|
||||
[[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
}
|
||||
|
||||
- (id<RCTEvent>)createScrollEventWithTag:(NSNumber *)viewTag value:(CGFloat)value
|
||||
{
|
||||
// The event value is the 3rd argument.
|
||||
NSArray *arguments = @[@1, @1, @{@"contentOffset": @{@"y": @(value)}}];
|
||||
return [[RCTFakeEvent alloc] initWithName:@"topScroll"
|
||||
viewTag:viewTag
|
||||
arguments:arguments];
|
||||
}
|
||||
|
||||
- (void)testNativeAnimatedEventDoUpdate
|
||||
{
|
||||
NSNumber *viewTag = @1000;
|
||||
[self createSimpleAnimatedView:viewTag withOpacity:0];
|
||||
|
||||
[_nodesManager addAnimatedEventToView:viewTag
|
||||
eventName:@"topScroll"
|
||||
eventMapping:@{@"animatedValueTag": @1,
|
||||
@"nativeEventPath": @[@"contentOffset", @"y"]}];
|
||||
|
||||
|
||||
|
||||
// Make sure that the update actually happened synchronously in `handleAnimatedEvent` and does
|
||||
// not wait for the next animation loop.
|
||||
[[_uiManager expect] synchronouslyUpdateViewOnUIThread:viewTag
|
||||
viewName:@"UIView"
|
||||
props:RCTPropChecker(@"opacity", @10)];
|
||||
[_nodesManager handleAnimatedEvent:[self createScrollEventWithTag:viewTag value:10]];
|
||||
[_uiManager verify];
|
||||
|
||||
[[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
[_nodesManager stepAnimations:_displayLink];
|
||||
[_uiManager verify];
|
||||
}
|
||||
|
||||
- (void)testNativeAnimatedEventDoNotUpdate
|
||||
{
|
||||
NSNumber *viewTag = @1000;
|
||||
[self createSimpleAnimatedView:viewTag withOpacity:0];
|
||||
|
||||
[_nodesManager addAnimatedEventToView:viewTag
|
||||
eventName:@"otherEvent"
|
||||
eventMapping:@{@"animatedValueTag": @1,
|
||||
@"nativeEventPath": @[@"contentOffset", @"y"]}];
|
||||
|
||||
[_nodesManager addAnimatedEventToView:@999
|
||||
eventName:@"topScroll"
|
||||
eventMapping:@{@"animatedValueTag": @1,
|
||||
@"nativeEventPath": @[@"contentOffset", @"y"]}];
|
||||
|
||||
[[_uiManager reject] synchronouslyUpdateViewOnUIThread:OCMOCK_ANY viewName:OCMOCK_ANY props:OCMOCK_ANY];
|
||||
[_nodesManager handleAnimatedEvent:[self createScrollEventWithTag:viewTag value:10]];
|
||||
[_uiManager verify];
|
||||
}
|
||||
|
||||
@end
|
|
@ -7,8 +7,8 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <React/RCTBridgeModule.h>
|
||||
|
||||
|
@ -29,9 +29,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
callBack:(nullable RCTResponseSenderBlock)callback;
|
||||
|
||||
- (void)startAnimation;
|
||||
- (void)stepAnimationWithTime:(NSTimeInterval)currentTime;
|
||||
- (void)stopAnimation;
|
||||
- (void)stepAnimation;
|
||||
- (void)removeAnimation;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
|
|
|
@ -61,19 +61,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
|
||||
- (void)startAnimation
|
||||
{
|
||||
_animationStartTime = CACurrentMediaTime();
|
||||
_animationCurrentTime = _animationStartTime;
|
||||
_animationStartTime = _animationCurrentTime = -1;
|
||||
_animationHasBegun = YES;
|
||||
}
|
||||
|
||||
- (void)stopAnimation
|
||||
{
|
||||
_animationHasFinished = YES;
|
||||
}
|
||||
|
||||
- (void)removeAnimation
|
||||
{
|
||||
[self stopAnimation];
|
||||
_valueNode = nil;
|
||||
if (_callback) {
|
||||
_callback(@[@{
|
||||
|
@ -82,14 +75,17 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
}
|
||||
}
|
||||
|
||||
- (void)stepAnimation
|
||||
- (void)stepAnimationWithTime:(NSTimeInterval)currentTime
|
||||
{
|
||||
if (!_animationHasBegun || _animationHasFinished || _frames.count == 0) {
|
||||
// Animation has not begun or animation has already finished.
|
||||
return;
|
||||
}
|
||||
|
||||
NSTimeInterval currentTime = CACurrentMediaTime();
|
||||
if (_animationStartTime == -1) {
|
||||
_animationStartTime = _animationCurrentTime = currentTime;
|
||||
}
|
||||
|
||||
_animationCurrentTime = currentTime;
|
||||
NSTimeInterval currentDuration = _animationCurrentTime - _animationStartTime;
|
||||
|
||||
|
@ -103,7 +99,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
// Update value and flag animation has ended.
|
||||
NSNumber *finalValue = _frames.lastObject;
|
||||
[self updateOutputWithFrameOutput:finalValue.doubleValue];
|
||||
[self stopAnimation];
|
||||
_animationHasFinished = YES;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,19 +71,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
|
||||
- (void)startAnimation
|
||||
{
|
||||
_animationStartTime = CACurrentMediaTime();
|
||||
_animationCurrentTime = _animationStartTime;
|
||||
_animationStartTime = _animationCurrentTime = -1;
|
||||
_animationHasBegun = YES;
|
||||
}
|
||||
|
||||
- (void)stopAnimation
|
||||
{
|
||||
_animationHasFinished = YES;
|
||||
}
|
||||
|
||||
- (void)removeAnimation
|
||||
{
|
||||
[self stopAnimation];
|
||||
_valueNode = nil;
|
||||
if (_callback) {
|
||||
_callback(@[@{
|
||||
|
@ -92,13 +85,17 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
}
|
||||
}
|
||||
|
||||
- (void)stepAnimation
|
||||
- (void)stepAnimationWithTime:(NSTimeInterval)currentTime
|
||||
{
|
||||
if (!_animationHasBegun || _animationHasFinished) {
|
||||
// Animation has not begun or animation has already finished.
|
||||
return;
|
||||
}
|
||||
|
||||
if (_animationStartTime == -1) {
|
||||
_animationStartTime = _animationCurrentTime = currentTime;
|
||||
}
|
||||
|
||||
// We are using a fixed time step and a maximum number of iterations.
|
||||
// The following post provides a lot of thoughts into how to build this
|
||||
// loop: http://gafferongames.com/game-physics/fix-your-timestep/
|
||||
|
@ -106,7 +103,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
// Velocity is based on seconds instead of milliseconds
|
||||
CGFloat step = TIMESTEP_MSEC / 1000;
|
||||
|
||||
NSTimeInterval currentTime = CACurrentMediaTime();
|
||||
NSInteger numSteps = floorf((currentTime - _animationCurrentTime) / step);
|
||||
_animationCurrentTime = currentTime;
|
||||
if (numSteps == 0) {
|
||||
|
@ -182,7 +178,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
[self onUpdate:_toValue];
|
||||
}
|
||||
|
||||
[self stopAnimation];
|
||||
_animationHasFinished = YES;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#import "RCTInterpolationAnimatedNode.h"
|
||||
|
||||
#import "RCTAnimationUtils.h"
|
||||
|
||||
@implementation RCTInterpolationAnimatedNode
|
||||
|
@ -53,20 +54,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (NSUInteger)findIndexOfNearestValue:(CGFloat)value
|
||||
inRange:(NSArray<NSNumber *> *)range
|
||||
{
|
||||
NSUInteger index;
|
||||
NSUInteger rangeCount = range.count;
|
||||
for (index = 1; index < rangeCount - 1; index++) {
|
||||
NSNumber *inputValue = range[index];
|
||||
if (inputValue.doubleValue >= value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index - 1;
|
||||
}
|
||||
|
||||
- (void)performUpdate
|
||||
{
|
||||
[super performUpdate];
|
||||
|
@ -75,19 +62,12 @@
|
|||
}
|
||||
|
||||
CGFloat inputValue = _parentNode.value;
|
||||
NSUInteger rangeIndex = [self findIndexOfNearestValue:inputValue inRange:_inputRange];
|
||||
NSNumber *inputMin = _inputRange[rangeIndex];
|
||||
NSNumber *inputMax = _inputRange[rangeIndex + 1];
|
||||
NSNumber *outputMin = _outputRange[rangeIndex];
|
||||
NSNumber *outputMax = _outputRange[rangeIndex + 1];
|
||||
|
||||
self.value = RCTInterpolateValue(inputValue,
|
||||
inputMin.doubleValue,
|
||||
inputMax.doubleValue,
|
||||
outputMin.doubleValue,
|
||||
outputMax.doubleValue,
|
||||
_extrapolateLeft,
|
||||
_extrapolateRight);
|
||||
self.value = RCTInterpolateValueInRange(inputValue,
|
||||
_inputRange,
|
||||
_outputRange,
|
||||
_extrapolateLeft,
|
||||
_extrapolateRight);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -17,7 +17,79 @@
|
|||
13E501EE1D07A6C9005F35D8 /* RCTStyleAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E31D07A6C9005F35D8 /* RCTStyleAnimatedNode.m */; };
|
||||
13E501EF1D07A6C9005F35D8 /* RCTTransformAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E51D07A6C9005F35D8 /* RCTTransformAnimatedNode.m */; };
|
||||
13E501F01D07A6C9005F35D8 /* RCTValueAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E71D07A6C9005F35D8 /* RCTValueAnimatedNode.m */; };
|
||||
192F69811E823F4A008692C7 /* RCTAnimationUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501B71D07A644005F35D8 /* RCTAnimationUtils.h */; };
|
||||
192F69821E823F4A008692C7 /* RCTNativeAnimatedModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501BD1D07A644005F35D8 /* RCTNativeAnimatedModule.h */; };
|
||||
192F69831E823F4A008692C7 /* RCTNativeAnimatedNodesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 94DA09161DC7971C00AEA8C9 /* RCTNativeAnimatedNodesManager.h */; };
|
||||
192F69841E823F4A008692C7 /* RCTAnimationDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 94C1294A1D4069170025F25C /* RCTAnimationDriver.h */; };
|
||||
192F69851E823F4A008692C7 /* RCTEventAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 19F00F201DC8847500113FEE /* RCTEventAnimation.h */; };
|
||||
192F69861E823F4A008692C7 /* RCTFrameAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 94C1294C1D4069170025F25C /* RCTFrameAnimation.h */; };
|
||||
192F69871E823F4A008692C7 /* RCTSpringAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 94C1294E1D4069170025F25C /* RCTSpringAnimation.h */; };
|
||||
192F69881E823F4A008692C7 /* RCTDivisionAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C9894931D999639008027DB /* RCTDivisionAnimatedNode.h */; };
|
||||
192F69891E823F4A008692C7 /* RCTDiffClampAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 193F64F21D776EC6004D1CAA /* RCTDiffClampAnimatedNode.h */; };
|
||||
192F698A1E823F4A008692C7 /* RCTAdditionAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501D61D07A6C9005F35D8 /* RCTAdditionAnimatedNode.h */; };
|
||||
192F698B1E823F4A008692C7 /* RCTAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501D81D07A6C9005F35D8 /* RCTAnimatedNode.h */; };
|
||||
192F698C1E823F4A008692C7 /* RCTInterpolationAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501DC1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.h */; };
|
||||
192F698D1E823F4A008692C7 /* RCTModuloAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 94DAE3F71D7334A70059942F /* RCTModuloAnimatedNode.h */; };
|
||||
192F698E1E823F4A008692C7 /* RCTMultiplicationAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501DE1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.h */; };
|
||||
192F698F1E823F4A008692C7 /* RCTPropsAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501E01D07A6C9005F35D8 /* RCTPropsAnimatedNode.h */; };
|
||||
192F69901E823F4A008692C7 /* RCTStyleAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501E21D07A6C9005F35D8 /* RCTStyleAnimatedNode.h */; };
|
||||
192F69911E823F4A008692C7 /* RCTTransformAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501E41D07A6C9005F35D8 /* RCTTransformAnimatedNode.h */; };
|
||||
192F69921E823F4A008692C7 /* RCTValueAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501E61D07A6C9005F35D8 /* RCTValueAnimatedNode.h */; };
|
||||
192F69941E823F78008692C7 /* RCTAnimationUtils.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501B71D07A644005F35D8 /* RCTAnimationUtils.h */; };
|
||||
192F69951E823F78008692C7 /* RCTNativeAnimatedModule.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501BD1D07A644005F35D8 /* RCTNativeAnimatedModule.h */; };
|
||||
192F69961E823F78008692C7 /* RCTNativeAnimatedNodesManager.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94DA09161DC7971C00AEA8C9 /* RCTNativeAnimatedNodesManager.h */; };
|
||||
192F69971E823F78008692C7 /* RCTAnimationDriver.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94C1294A1D4069170025F25C /* RCTAnimationDriver.h */; };
|
||||
192F69981E823F78008692C7 /* RCTEventAnimation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 19F00F201DC8847500113FEE /* RCTEventAnimation.h */; };
|
||||
192F69991E823F78008692C7 /* RCTFrameAnimation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94C1294C1D4069170025F25C /* RCTFrameAnimation.h */; };
|
||||
192F699A1E823F78008692C7 /* RCTSpringAnimation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94C1294E1D4069170025F25C /* RCTSpringAnimation.h */; };
|
||||
192F699B1E823F78008692C7 /* RCTDivisionAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5C9894931D999639008027DB /* RCTDivisionAnimatedNode.h */; };
|
||||
192F699C1E823F78008692C7 /* RCTDiffClampAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 193F64F21D776EC6004D1CAA /* RCTDiffClampAnimatedNode.h */; };
|
||||
192F699D1E823F78008692C7 /* RCTAdditionAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501D61D07A6C9005F35D8 /* RCTAdditionAnimatedNode.h */; };
|
||||
192F699E1E823F78008692C7 /* RCTAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501D81D07A6C9005F35D8 /* RCTAnimatedNode.h */; };
|
||||
192F699F1E823F78008692C7 /* RCTInterpolationAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501DC1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.h */; };
|
||||
192F69A01E823F78008692C7 /* RCTModuloAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94DAE3F71D7334A70059942F /* RCTModuloAnimatedNode.h */; };
|
||||
192F69A11E823F78008692C7 /* RCTMultiplicationAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501DE1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.h */; };
|
||||
192F69A21E823F78008692C7 /* RCTPropsAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E01D07A6C9005F35D8 /* RCTPropsAnimatedNode.h */; };
|
||||
192F69A31E823F78008692C7 /* RCTStyleAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E21D07A6C9005F35D8 /* RCTStyleAnimatedNode.h */; };
|
||||
192F69A41E823F78008692C7 /* RCTTransformAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E41D07A6C9005F35D8 /* RCTTransformAnimatedNode.h */; };
|
||||
192F69A51E823F78008692C7 /* RCTValueAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E61D07A6C9005F35D8 /* RCTValueAnimatedNode.h */; };
|
||||
193F64F41D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 193F64F31D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m */; };
|
||||
1980B70E1E80D1C4004DC789 /* RCTAnimationUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501B71D07A644005F35D8 /* RCTAnimationUtils.h */; };
|
||||
1980B7101E80D1C4004DC789 /* RCTNativeAnimatedModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501BD1D07A644005F35D8 /* RCTNativeAnimatedModule.h */; };
|
||||
1980B7121E80D1C4004DC789 /* RCTNativeAnimatedNodesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 94DA09161DC7971C00AEA8C9 /* RCTNativeAnimatedNodesManager.h */; };
|
||||
1980B7141E80D1C4004DC789 /* RCTAnimationDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 94C1294A1D4069170025F25C /* RCTAnimationDriver.h */; };
|
||||
1980B7151E80D1C4004DC789 /* RCTEventAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 19F00F201DC8847500113FEE /* RCTEventAnimation.h */; };
|
||||
1980B7171E80D1C4004DC789 /* RCTFrameAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 94C1294C1D4069170025F25C /* RCTFrameAnimation.h */; };
|
||||
1980B7191E80D1C4004DC789 /* RCTSpringAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 94C1294E1D4069170025F25C /* RCTSpringAnimation.h */; };
|
||||
1980B71B1E80D1C4004DC789 /* RCTDivisionAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C9894931D999639008027DB /* RCTDivisionAnimatedNode.h */; };
|
||||
1980B71D1E80D1C4004DC789 /* RCTDiffClampAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 193F64F21D776EC6004D1CAA /* RCTDiffClampAnimatedNode.h */; };
|
||||
1980B71F1E80D1C4004DC789 /* RCTAdditionAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501D61D07A6C9005F35D8 /* RCTAdditionAnimatedNode.h */; };
|
||||
1980B7211E80D1C4004DC789 /* RCTAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501D81D07A6C9005F35D8 /* RCTAnimatedNode.h */; };
|
||||
1980B7231E80D1C4004DC789 /* RCTInterpolationAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501DC1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.h */; };
|
||||
1980B7251E80D1C4004DC789 /* RCTModuloAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 94DAE3F71D7334A70059942F /* RCTModuloAnimatedNode.h */; };
|
||||
1980B7271E80D1C4004DC789 /* RCTMultiplicationAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501DE1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.h */; };
|
||||
1980B7291E80D1C4004DC789 /* RCTPropsAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501E01D07A6C9005F35D8 /* RCTPropsAnimatedNode.h */; };
|
||||
1980B72B1E80D1C4004DC789 /* RCTStyleAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501E21D07A6C9005F35D8 /* RCTStyleAnimatedNode.h */; };
|
||||
1980B72D1E80D1C4004DC789 /* RCTTransformAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501E41D07A6C9005F35D8 /* RCTTransformAnimatedNode.h */; };
|
||||
1980B72F1E80D1C4004DC789 /* RCTValueAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501E61D07A6C9005F35D8 /* RCTValueAnimatedNode.h */; };
|
||||
1980B7321E80D259004DC789 /* RCTAnimationUtils.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501B71D07A644005F35D8 /* RCTAnimationUtils.h */; };
|
||||
1980B7351E80DD6F004DC789 /* RCTNativeAnimatedModule.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501BD1D07A644005F35D8 /* RCTNativeAnimatedModule.h */; };
|
||||
1980B7361E80DD6F004DC789 /* RCTNativeAnimatedNodesManager.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94DA09161DC7971C00AEA8C9 /* RCTNativeAnimatedNodesManager.h */; };
|
||||
1980B7371E80DD6F004DC789 /* RCTAnimationDriver.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94C1294A1D4069170025F25C /* RCTAnimationDriver.h */; };
|
||||
1980B7381E80DD6F004DC789 /* RCTEventAnimation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 19F00F201DC8847500113FEE /* RCTEventAnimation.h */; };
|
||||
1980B7391E80DD6F004DC789 /* RCTFrameAnimation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94C1294C1D4069170025F25C /* RCTFrameAnimation.h */; };
|
||||
1980B73A1E80DD6F004DC789 /* RCTSpringAnimation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94C1294E1D4069170025F25C /* RCTSpringAnimation.h */; };
|
||||
1980B73B1E80DD6F004DC789 /* RCTDivisionAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5C9894931D999639008027DB /* RCTDivisionAnimatedNode.h */; };
|
||||
1980B73C1E80DD6F004DC789 /* RCTDiffClampAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 193F64F21D776EC6004D1CAA /* RCTDiffClampAnimatedNode.h */; };
|
||||
1980B73D1E80DD6F004DC789 /* RCTAdditionAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501D61D07A6C9005F35D8 /* RCTAdditionAnimatedNode.h */; };
|
||||
1980B73E1E80DD6F004DC789 /* RCTAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501D81D07A6C9005F35D8 /* RCTAnimatedNode.h */; };
|
||||
1980B73F1E80DD6F004DC789 /* RCTInterpolationAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501DC1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.h */; };
|
||||
1980B7401E80DD6F004DC789 /* RCTModuloAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94DAE3F71D7334A70059942F /* RCTModuloAnimatedNode.h */; };
|
||||
1980B7411E80DD6F004DC789 /* RCTMultiplicationAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501DE1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.h */; };
|
||||
1980B7421E80DD6F004DC789 /* RCTPropsAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E01D07A6C9005F35D8 /* RCTPropsAnimatedNode.h */; };
|
||||
1980B7431E80DD6F004DC789 /* RCTStyleAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E21D07A6C9005F35D8 /* RCTStyleAnimatedNode.h */; };
|
||||
1980B7441E80DD6F004DC789 /* RCTTransformAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E41D07A6C9005F35D8 /* RCTTransformAnimatedNode.h */; };
|
||||
1980B7451E80DD6F004DC789 /* RCTValueAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E61D07A6C9005F35D8 /* RCTValueAnimatedNode.h */; };
|
||||
19F00F221DC8847500113FEE /* RCTEventAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 19F00F211DC8847500113FEE /* RCTEventAnimation.m */; };
|
||||
19F00F231DC8848E00113FEE /* RCTEventAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 19F00F211DC8847500113FEE /* RCTEventAnimation.m */; };
|
||||
2D3B5EF21D9B0B3100451313 /* RCTAnimationUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501B81D07A644005F35D8 /* RCTAnimationUtils.m */; };
|
||||
|
@ -43,6 +115,63 @@
|
|||
94DAE3F91D7334A70059942F /* RCTModuloAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 94DAE3F81D7334A70059942F /* RCTModuloAnimatedNode.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
192F69931E823F4F008692C7 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = include/RCTAnimation;
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
192F69941E823F78008692C7 /* RCTAnimationUtils.h in CopyFiles */,
|
||||
192F69951E823F78008692C7 /* RCTNativeAnimatedModule.h in CopyFiles */,
|
||||
192F69961E823F78008692C7 /* RCTNativeAnimatedNodesManager.h in CopyFiles */,
|
||||
192F69971E823F78008692C7 /* RCTAnimationDriver.h in CopyFiles */,
|
||||
192F69981E823F78008692C7 /* RCTEventAnimation.h in CopyFiles */,
|
||||
192F69991E823F78008692C7 /* RCTFrameAnimation.h in CopyFiles */,
|
||||
192F699A1E823F78008692C7 /* RCTSpringAnimation.h in CopyFiles */,
|
||||
192F699B1E823F78008692C7 /* RCTDivisionAnimatedNode.h in CopyFiles */,
|
||||
192F699C1E823F78008692C7 /* RCTDiffClampAnimatedNode.h in CopyFiles */,
|
||||
192F699D1E823F78008692C7 /* RCTAdditionAnimatedNode.h in CopyFiles */,
|
||||
192F699E1E823F78008692C7 /* RCTAnimatedNode.h in CopyFiles */,
|
||||
192F699F1E823F78008692C7 /* RCTInterpolationAnimatedNode.h in CopyFiles */,
|
||||
192F69A01E823F78008692C7 /* RCTModuloAnimatedNode.h in CopyFiles */,
|
||||
192F69A11E823F78008692C7 /* RCTMultiplicationAnimatedNode.h in CopyFiles */,
|
||||
192F69A21E823F78008692C7 /* RCTPropsAnimatedNode.h in CopyFiles */,
|
||||
192F69A31E823F78008692C7 /* RCTStyleAnimatedNode.h in CopyFiles */,
|
||||
192F69A41E823F78008692C7 /* RCTTransformAnimatedNode.h in CopyFiles */,
|
||||
192F69A51E823F78008692C7 /* RCTValueAnimatedNode.h in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
1980B7311E80D21C004DC789 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = include/RCTAnimation;
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
1980B7351E80DD6F004DC789 /* RCTNativeAnimatedModule.h in CopyFiles */,
|
||||
1980B7361E80DD6F004DC789 /* RCTNativeAnimatedNodesManager.h in CopyFiles */,
|
||||
1980B7371E80DD6F004DC789 /* RCTAnimationDriver.h in CopyFiles */,
|
||||
1980B7381E80DD6F004DC789 /* RCTEventAnimation.h in CopyFiles */,
|
||||
1980B7391E80DD6F004DC789 /* RCTFrameAnimation.h in CopyFiles */,
|
||||
1980B73A1E80DD6F004DC789 /* RCTSpringAnimation.h in CopyFiles */,
|
||||
1980B73B1E80DD6F004DC789 /* RCTDivisionAnimatedNode.h in CopyFiles */,
|
||||
1980B73C1E80DD6F004DC789 /* RCTDiffClampAnimatedNode.h in CopyFiles */,
|
||||
1980B73D1E80DD6F004DC789 /* RCTAdditionAnimatedNode.h in CopyFiles */,
|
||||
1980B73E1E80DD6F004DC789 /* RCTAnimatedNode.h in CopyFiles */,
|
||||
1980B73F1E80DD6F004DC789 /* RCTInterpolationAnimatedNode.h in CopyFiles */,
|
||||
1980B7401E80DD6F004DC789 /* RCTModuloAnimatedNode.h in CopyFiles */,
|
||||
1980B7411E80DD6F004DC789 /* RCTMultiplicationAnimatedNode.h in CopyFiles */,
|
||||
1980B7421E80DD6F004DC789 /* RCTPropsAnimatedNode.h in CopyFiles */,
|
||||
1980B7431E80DD6F004DC789 /* RCTStyleAnimatedNode.h in CopyFiles */,
|
||||
1980B7441E80DD6F004DC789 /* RCTTransformAnimatedNode.h in CopyFiles */,
|
||||
1980B7451E80DD6F004DC789 /* RCTValueAnimatedNode.h in CopyFiles */,
|
||||
1980B7321E80D259004DC789 /* RCTAnimationUtils.h in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
134814201AA4EA6300B7C361 /* libRCTAnimation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTAnimation.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13E501B71D07A644005F35D8 /* RCTAnimationUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTAnimationUtils.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
|
@ -153,12 +282,67 @@
|
|||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
192F69801E823F2E008692C7 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
192F69811E823F4A008692C7 /* RCTAnimationUtils.h in Headers */,
|
||||
192F69821E823F4A008692C7 /* RCTNativeAnimatedModule.h in Headers */,
|
||||
192F69831E823F4A008692C7 /* RCTNativeAnimatedNodesManager.h in Headers */,
|
||||
192F69841E823F4A008692C7 /* RCTAnimationDriver.h in Headers */,
|
||||
192F69851E823F4A008692C7 /* RCTEventAnimation.h in Headers */,
|
||||
192F69861E823F4A008692C7 /* RCTFrameAnimation.h in Headers */,
|
||||
192F69871E823F4A008692C7 /* RCTSpringAnimation.h in Headers */,
|
||||
192F69881E823F4A008692C7 /* RCTDivisionAnimatedNode.h in Headers */,
|
||||
192F69891E823F4A008692C7 /* RCTDiffClampAnimatedNode.h in Headers */,
|
||||
192F698A1E823F4A008692C7 /* RCTAdditionAnimatedNode.h in Headers */,
|
||||
192F698B1E823F4A008692C7 /* RCTAnimatedNode.h in Headers */,
|
||||
192F698C1E823F4A008692C7 /* RCTInterpolationAnimatedNode.h in Headers */,
|
||||
192F698D1E823F4A008692C7 /* RCTModuloAnimatedNode.h in Headers */,
|
||||
192F698E1E823F4A008692C7 /* RCTMultiplicationAnimatedNode.h in Headers */,
|
||||
192F698F1E823F4A008692C7 /* RCTPropsAnimatedNode.h in Headers */,
|
||||
192F69901E823F4A008692C7 /* RCTStyleAnimatedNode.h in Headers */,
|
||||
192F69911E823F4A008692C7 /* RCTTransformAnimatedNode.h in Headers */,
|
||||
192F69921E823F4A008692C7 /* RCTValueAnimatedNode.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
1980B70D1E80D1B5004DC789 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1980B70E1E80D1C4004DC789 /* RCTAnimationUtils.h in Headers */,
|
||||
1980B7101E80D1C4004DC789 /* RCTNativeAnimatedModule.h in Headers */,
|
||||
1980B7121E80D1C4004DC789 /* RCTNativeAnimatedNodesManager.h in Headers */,
|
||||
1980B7141E80D1C4004DC789 /* RCTAnimationDriver.h in Headers */,
|
||||
1980B7151E80D1C4004DC789 /* RCTEventAnimation.h in Headers */,
|
||||
1980B7171E80D1C4004DC789 /* RCTFrameAnimation.h in Headers */,
|
||||
1980B7191E80D1C4004DC789 /* RCTSpringAnimation.h in Headers */,
|
||||
1980B71B1E80D1C4004DC789 /* RCTDivisionAnimatedNode.h in Headers */,
|
||||
1980B71D1E80D1C4004DC789 /* RCTDiffClampAnimatedNode.h in Headers */,
|
||||
1980B71F1E80D1C4004DC789 /* RCTAdditionAnimatedNode.h in Headers */,
|
||||
1980B7211E80D1C4004DC789 /* RCTAnimatedNode.h in Headers */,
|
||||
1980B7231E80D1C4004DC789 /* RCTInterpolationAnimatedNode.h in Headers */,
|
||||
1980B7251E80D1C4004DC789 /* RCTModuloAnimatedNode.h in Headers */,
|
||||
1980B7271E80D1C4004DC789 /* RCTMultiplicationAnimatedNode.h in Headers */,
|
||||
1980B7291E80D1C4004DC789 /* RCTPropsAnimatedNode.h in Headers */,
|
||||
1980B72B1E80D1C4004DC789 /* RCTStyleAnimatedNode.h in Headers */,
|
||||
1980B72D1E80D1C4004DC789 /* RCTTransformAnimatedNode.h in Headers */,
|
||||
1980B72F1E80D1C4004DC789 /* RCTValueAnimatedNode.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
2D2A281F1D9B03D100D4039D /* RCTAnimation-tvOS */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 2D2A28281D9B03D100D4039D /* Build configuration list for PBXNativeTarget "RCTAnimation-tvOS" */;
|
||||
buildPhases = (
|
||||
2D2A281C1D9B03D100D4039D /* Sources */,
|
||||
192F69801E823F2E008692C7 /* Headers */,
|
||||
192F69931E823F4F008692C7 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -174,6 +358,8 @@
|
|||
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTAnimation" */;
|
||||
buildPhases = (
|
||||
58B511D71A9E6C8500147676 /* Sources */,
|
||||
1980B70D1E80D1B5004DC789 /* Headers */,
|
||||
1980B7311E80D21C004DC789 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
|
|
@ -16,6 +16,12 @@ static NSString *const EXTRAPOLATE_TYPE_IDENTITY = @"identity";
|
|||
static NSString *const EXTRAPOLATE_TYPE_CLAMP = @"clamp";
|
||||
static NSString *const EXTRAPOLATE_TYPE_EXTEND = @"extend";
|
||||
|
||||
RCT_EXTERN CGFloat RCTInterpolateValueInRange(CGFloat value,
|
||||
NSArray<NSNumber *> *inputRange,
|
||||
NSArray<NSNumber *> *outputRange,
|
||||
NSString *extrapolateLeft,
|
||||
NSString *extrapolateRight);
|
||||
|
||||
RCT_EXTERN CGFloat RCTInterpolateValue(CGFloat value,
|
||||
CGFloat inputMin,
|
||||
CGFloat inputMax,
|
||||
|
|
|
@ -11,6 +11,19 @@
|
|||
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
static NSUInteger _RCTFindIndexOfNearestValue(CGFloat value, NSArray<NSNumber *> *range)
|
||||
{
|
||||
NSUInteger index;
|
||||
NSUInteger rangeCount = range.count;
|
||||
for (index = 1; index < rangeCount - 1; index++) {
|
||||
NSNumber *inputValue = range[index];
|
||||
if (inputValue.doubleValue >= value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates value by remapping it linearly fromMin->fromMax to toMin->toMax
|
||||
*/
|
||||
|
@ -49,6 +62,30 @@ CGFloat RCTInterpolateValue(CGFloat value,
|
|||
return outputMin + (value - inputMin) * (outputMax - outputMin) / (inputMax - inputMin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates value by mapping it from the inputRange to the outputRange.
|
||||
*/
|
||||
CGFloat RCTInterpolateValueInRange(CGFloat value,
|
||||
NSArray<NSNumber *> *inputRange,
|
||||
NSArray<NSNumber *> *outputRange,
|
||||
NSString *extrapolateLeft,
|
||||
NSString *extrapolateRight)
|
||||
{
|
||||
NSUInteger rangeIndex = _RCTFindIndexOfNearestValue(value, inputRange);
|
||||
CGFloat inputMin = inputRange[rangeIndex].doubleValue;
|
||||
CGFloat inputMax = inputRange[rangeIndex + 1].doubleValue;
|
||||
CGFloat outputMin = outputRange[rangeIndex].doubleValue;
|
||||
CGFloat outputMax = outputRange[rangeIndex + 1].doubleValue;
|
||||
|
||||
return RCTInterpolateValue(value,
|
||||
inputMin,
|
||||
inputMax,
|
||||
outputMin,
|
||||
outputMax,
|
||||
extrapolateLeft,
|
||||
extrapolateRight);
|
||||
}
|
||||
|
||||
CGFloat RCTRadiansToDegrees(CGFloat radians)
|
||||
{
|
||||
return radians * 180.0 / M_PI;
|
||||
|
|
|
@ -161,9 +161,8 @@ RCT_EXPORT_METHOD(startListeningToAnimatedNodeValue:(nonnull NSNumber *)tag)
|
|||
|
||||
RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag)
|
||||
{
|
||||
__weak id<RCTValueAnimatedNodeObserver> valueObserver = self;
|
||||
[self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
|
||||
[nodesManager stopListeningToAnimatedNodeValue:tag valueObserver:valueObserver];
|
||||
[nodesManager stopListeningToAnimatedNodeValue:tag];
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
@ -9,17 +9,18 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <RCTAnimation/RCTValueAnimatedNode.h>
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTUIManager.h>
|
||||
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
|
||||
@interface RCTNativeAnimatedNodesManager : NSObject
|
||||
|
||||
- (nonnull instancetype)initWithUIManager:(nonnull RCTUIManager *)uiManager;
|
||||
|
||||
- (void)updateAnimations;
|
||||
|
||||
- (void)stepAnimations:(nonnull CADisplayLink *)displaylink;
|
||||
|
||||
// graph
|
||||
|
||||
- (void)createAnimatedNode:(nonnull NSNumber *)tag
|
||||
|
@ -80,7 +81,6 @@
|
|||
- (void)startListeningToAnimatedNodeValue:(nonnull NSNumber *)tag
|
||||
valueObserver:(nonnull id<RCTValueAnimatedNodeObserver>)valueObserver;
|
||||
|
||||
- (void)stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag
|
||||
valueObserver:(nonnull id<RCTValueAnimatedNodeObserver>)valueObserver;
|
||||
- (void)stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag;
|
||||
|
||||
@end
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
{
|
||||
for (id<RCTAnimationDriver> driver in _activeAnimations) {
|
||||
if ([driver.animationId isEqual:animationId]) {
|
||||
[driver removeAnimation];
|
||||
[driver stopAnimation];
|
||||
[_activeAnimations removeObject:driver];
|
||||
break;
|
||||
}
|
||||
|
@ -325,11 +325,10 @@
|
|||
}
|
||||
|
||||
- (void)stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag
|
||||
valueObserver:(id<RCTValueAnimatedNodeObserver>)valueObserver
|
||||
{
|
||||
RCTAnimatedNode *node = _animationNodes[tag];
|
||||
if ([node isKindOfClass:[RCTValueAnimatedNode class]]) {
|
||||
((RCTValueAnimatedNode *)node).valueObserver = valueObserver;
|
||||
((RCTValueAnimatedNode *)node).valueObserver = nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,7 +338,7 @@
|
|||
- (void)startAnimationLoopIfNeeded
|
||||
{
|
||||
if (!_displayLink && _activeAnimations.count > 0) {
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(stepAnimations)];
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(stepAnimations:)];
|
||||
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
}
|
||||
|
@ -359,17 +358,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (void)stepAnimations
|
||||
- (void)stepAnimations:(CADisplayLink *)displaylink
|
||||
{
|
||||
NSTimeInterval time = displaylink.timestamp;
|
||||
for (id<RCTAnimationDriver> animationDriver in _activeAnimations) {
|
||||
[animationDriver stepAnimation];
|
||||
[animationDriver stepAnimationWithTime:time];
|
||||
}
|
||||
|
||||
[self updateAnimations];
|
||||
|
||||
for (id<RCTAnimationDriver> animationDriver in [_activeAnimations copy]) {
|
||||
if (animationDriver.animationHasFinished) {
|
||||
[animationDriver removeAnimation];
|
||||
[animationDriver stopAnimation];
|
||||
[_activeAnimations removeObject:animationDriver];
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue