Add support for springs for NativeAnimated on iOS
Summary: This diff adds support for native spring animations on iOS. This overlaps some spring work done by kmagiera on the Android side of things. **Test plan (required)** Run UIExplorer NativeAnimated examples before and after - compare the results. Pay special attention to the spring examples. Closes https://github.com/facebook/react-native/pull/9048 Differential Revision: D4056088 Pulled By: foghina fbshipit-source-id: a593408cb61cb850572bab4a0884f7157cece656
This commit is contained in:
parent
5e94114497
commit
d950db4ef7
|
@ -14,20 +14,17 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RCTAnimationDriverNode : NSObject
|
||||
@protocol RCTAnimationDriver <NSObject>
|
||||
|
||||
@property (nonatomic, readonly) NSNumber *animationId;
|
||||
@property (nonatomic, readonly) NSNumber *outputValue;
|
||||
|
||||
@property (nonatomic, readonly) RCTValueAnimatedNode *valueNode;
|
||||
@property (nonatomic, readonly) BOOL animationHasBegun;
|
||||
@property (nonatomic, readonly) BOOL animationHasFinished;
|
||||
|
||||
- (instancetype)initWithId:(NSNumber *)animationId
|
||||
delay:(NSTimeInterval)delay
|
||||
toValue:(CGFloat)toValue
|
||||
frames:(NSArray<NSNumber *> *)frames
|
||||
config:(NSDictionary *)config
|
||||
forNode:(RCTValueAnimatedNode *)valueNode
|
||||
callBack:(nullable RCTResponseSenderBlock)callback NS_DESIGNATED_INITIALIZER;
|
||||
callBack:(nullable RCTResponseSenderBlock)callback;
|
||||
|
||||
- (void)startAnimation;
|
||||
- (void)stopAnimation;
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTAnimationDriver.h"
|
||||
|
||||
@interface RCTFrameAnimation : NSObject<RCTAnimationDriver>
|
||||
|
||||
@end
|
|
@ -7,17 +7,27 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTAnimationDriverNode.h"
|
||||
#import "RCTFrameAnimation.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTAnimationUtils.h"
|
||||
#import "RCTDefines.h"
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
|
||||
const double SINGLE_FRAME_INTERVAL = 1.0 / 60.0;
|
||||
|
||||
@implementation RCTAnimationDriverNode
|
||||
@interface RCTFrameAnimation ()
|
||||
|
||||
@property (nonatomic, strong) NSNumber *animationId;
|
||||
@property (nonatomic, strong) RCTValueAnimatedNode *valueNode;
|
||||
@property (nonatomic, assign) BOOL animationHasBegun;
|
||||
@property (nonatomic, assign) BOOL animationHasFinished;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTFrameAnimation
|
||||
{
|
||||
NSArray<NSNumber *> *_frames;
|
||||
CGFloat _toValue;
|
||||
|
@ -25,25 +35,25 @@ const double SINGLE_FRAME_INTERVAL = 1.0 / 60.0;
|
|||
NSTimeInterval _delay;
|
||||
NSTimeInterval _animationStartTime;
|
||||
NSTimeInterval _animationCurrentTime;
|
||||
RCTValueAnimatedNode *_valueNode;
|
||||
RCTResponseSenderBlock _callback;
|
||||
}
|
||||
|
||||
- (instancetype)initWithId:(nonnull NSNumber *)animationId
|
||||
delay:(NSTimeInterval)delay
|
||||
toValue:(CGFloat)toValue
|
||||
frames:(nonnull NSArray<NSNumber *> *)frames
|
||||
forNode:(nonnull RCTValueAnimatedNode *)valueNode
|
||||
callBack:(nullable RCTResponseSenderBlock)callback
|
||||
- (instancetype)initWithId:(NSNumber *)animationId
|
||||
config:(NSDictionary *)config
|
||||
forNode:(RCTValueAnimatedNode *)valueNode
|
||||
callBack:(nullable RCTResponseSenderBlock)callback;
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
NSNumber *toValue = [RCTConvert NSNumber:config[@"toValue"]] ?: @1;
|
||||
NSTimeInterval delay = [RCTConvert double:config[@"delay"]];
|
||||
NSArray<NSNumber *> *frames = [RCTConvert NSNumberArray:config[@"frames"]];
|
||||
|
||||
_animationId = animationId;
|
||||
_toValue = toValue;
|
||||
_toValue = toValue.floatValue;
|
||||
_fromValue = valueNode.value;
|
||||
_valueNode = valueNode;
|
||||
_delay = delay;
|
||||
_frames = [frames copy];
|
||||
_outputValue = @0;
|
||||
_callback = [callback copy];
|
||||
}
|
||||
return self;
|
||||
|
@ -135,7 +145,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
EXTRAPOLATE_TYPE_EXTEND,
|
||||
EXTRAPOLATE_TYPE_EXTEND);
|
||||
|
||||
_outputValue = @(outputValue);
|
||||
_valueNode.value = outputValue;
|
||||
[_valueNode setNeedsUpdate];
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTAnimationDriver.h"
|
||||
|
||||
@interface RCTSpringAnimation : NSObject<RCTAnimationDriver>
|
||||
|
||||
@end
|
|
@ -0,0 +1,200 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTSpringAnimation.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTAnimationUtils.h"
|
||||
#import "RCTDefines.h"
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
|
||||
@interface RCTSpringAnimation ()
|
||||
|
||||
@property (nonatomic, strong) NSNumber *animationId;
|
||||
@property (nonatomic, strong) RCTValueAnimatedNode *valueNode;
|
||||
@property (nonatomic, assign) BOOL animationHasBegun;
|
||||
@property (nonatomic, assign) BOOL animationHasFinished;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTSpringAnimation
|
||||
{
|
||||
CGFloat _toValue;
|
||||
CGFloat _fromValue;
|
||||
BOOL _overshootClamping;
|
||||
CGFloat _restDisplacementThreshold;
|
||||
CGFloat _restSpeedThreshold;
|
||||
CGFloat _tension;
|
||||
CGFloat _friction;
|
||||
CGFloat _initialVelocity;
|
||||
NSTimeInterval _animationStartTime;
|
||||
NSTimeInterval _animationCurrentTime;
|
||||
RCTResponseSenderBlock _callback;
|
||||
|
||||
CGFloat _lastPosition;
|
||||
CGFloat _lastVelocity;
|
||||
}
|
||||
|
||||
- (instancetype)initWithId:(NSNumber *)animationId
|
||||
config:(NSDictionary *)config
|
||||
forNode:(RCTValueAnimatedNode *)valueNode
|
||||
callBack:(nullable RCTResponseSenderBlock)callback
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_animationId = animationId;
|
||||
_toValue = [RCTConvert CGFloat:config[@"toValue"]];
|
||||
_fromValue = valueNode.value;
|
||||
_valueNode = valueNode;
|
||||
_overshootClamping = [RCTConvert BOOL:config[@"overshootClamping"]];
|
||||
_restDisplacementThreshold = [RCTConvert CGFloat:config[@"restDisplacementThreshold"]];
|
||||
_restSpeedThreshold = [RCTConvert CGFloat:config[@"restSpeedThreshold"]];
|
||||
_tension = [RCTConvert CGFloat:config[@"tension"]];
|
||||
_friction = [RCTConvert CGFloat:config[@"friction"]];
|
||||
_initialVelocity = [RCTConvert CGFloat:config[@"initialVelocity"]];
|
||||
_callback = [callback copy];
|
||||
|
||||
_lastPosition = _fromValue;
|
||||
_lastVelocity = _initialVelocity;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
|
||||
- (void)startAnimation
|
||||
{
|
||||
_animationStartTime = CACurrentMediaTime();
|
||||
_animationCurrentTime = _animationStartTime;
|
||||
_animationHasBegun = YES;
|
||||
}
|
||||
|
||||
- (void)stopAnimation
|
||||
{
|
||||
_animationHasFinished = YES;
|
||||
}
|
||||
|
||||
- (void)removeAnimation
|
||||
{
|
||||
[self stopAnimation];
|
||||
_valueNode = nil;
|
||||
if (_callback) {
|
||||
_callback(@[@{
|
||||
@"finished": @(_animationHasFinished)
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stepAnimation
|
||||
{
|
||||
if (!_animationHasBegun || _animationHasFinished) {
|
||||
// Animation has not begun or animation has already finished.
|
||||
return;
|
||||
}
|
||||
|
||||
// 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/
|
||||
CGFloat TIMESTEP_MSEC = 1;
|
||||
// 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) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGFloat position = _lastPosition;
|
||||
CGFloat velocity = _lastVelocity;
|
||||
|
||||
CGFloat tempPosition = _lastPosition;
|
||||
CGFloat tempVelocity = _lastVelocity;
|
||||
|
||||
for (NSInteger i = 0; i < numSteps; ++i) {
|
||||
// This is using RK4. A good blog post to understand how it works:
|
||||
// http://gafferongames.com/game-physics/integration-basics/
|
||||
CGFloat aVelocity = velocity;
|
||||
CGFloat aAcceleration = _tension * (_toValue - tempPosition) - _friction * tempVelocity;
|
||||
tempPosition = position + aVelocity * step / 2;
|
||||
tempVelocity = velocity + aAcceleration * step / 2;
|
||||
|
||||
CGFloat bVelocity = tempVelocity;
|
||||
CGFloat bAcceleration = _tension * (_toValue - tempPosition) - _friction * tempVelocity;
|
||||
tempPosition = position + bVelocity * step / 2;
|
||||
tempVelocity = velocity + bAcceleration * step / 2;
|
||||
|
||||
CGFloat cVelocity = tempVelocity;
|
||||
CGFloat cAcceleration = _tension * (_toValue - tempPosition) - _friction * tempVelocity;
|
||||
tempPosition = position + cVelocity * step / 2;
|
||||
tempVelocity = velocity + cAcceleration * step / 2;
|
||||
|
||||
CGFloat dVelocity = tempVelocity;
|
||||
CGFloat dAcceleration = _tension * (_toValue - tempPosition) - _friction * tempVelocity;
|
||||
tempPosition = position + cVelocity * step / 2;
|
||||
tempVelocity = velocity + cAcceleration * step / 2;
|
||||
|
||||
CGFloat dxdt = (aVelocity + 2 * (bVelocity + cVelocity) + dVelocity) / 6;
|
||||
CGFloat dvdt = (aAcceleration + 2 * (bAcceleration + cAcceleration) + dAcceleration) / 6;
|
||||
|
||||
position += dxdt * step;
|
||||
velocity += dvdt * step;
|
||||
}
|
||||
|
||||
_lastPosition = position;
|
||||
_lastVelocity = velocity;
|
||||
|
||||
[self onUpdate:position];
|
||||
|
||||
if (_animationHasFinished) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Conditions for stopping the spring animation
|
||||
BOOL isOvershooting = NO;
|
||||
if (_overshootClamping && _tension != 0) {
|
||||
if (_fromValue < _toValue) {
|
||||
isOvershooting = position > _toValue;
|
||||
} else {
|
||||
isOvershooting = position < _toValue;
|
||||
}
|
||||
}
|
||||
BOOL isVelocity = ABS(velocity) <= _restSpeedThreshold;
|
||||
BOOL isDisplacement = YES;
|
||||
if (_tension != 0) {
|
||||
isDisplacement = ABS(_toValue - position) <= _restDisplacementThreshold;
|
||||
}
|
||||
|
||||
if (isOvershooting || (isVelocity && isDisplacement)) {
|
||||
if (_tension != 0) {
|
||||
// Ensure that we end up with a round value
|
||||
if (_animationHasFinished) {
|
||||
return;
|
||||
}
|
||||
[self onUpdate:_toValue];
|
||||
}
|
||||
|
||||
[self stopAnimation];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onUpdate:(CGFloat)outputValue
|
||||
{
|
||||
_valueNode.value = outputValue;
|
||||
[_valueNode setNeedsUpdate];
|
||||
}
|
||||
|
||||
- (void)cleanupAnimationUpdate
|
||||
{
|
||||
[_valueNode cleanupAnimationUpdate];
|
||||
}
|
||||
|
||||
@end
|
|
@ -12,7 +12,6 @@
|
|||
13E501D41D07A644005F35D8 /* RCTViewPropertyMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501C81D07A644005F35D8 /* RCTViewPropertyMapper.m */; };
|
||||
13E501E81D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501D71D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m */; };
|
||||
13E501E91D07A6C9005F35D8 /* RCTAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501D91D07A6C9005F35D8 /* RCTAnimatedNode.m */; };
|
||||
13E501EA1D07A6C9005F35D8 /* RCTAnimationDriverNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DB1D07A6C9005F35D8 /* RCTAnimationDriverNode.m */; };
|
||||
13E501EB1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DD1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m */; };
|
||||
13E501EC1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DF1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.m */; };
|
||||
13E501ED1D07A6C9005F35D8 /* RCTPropsAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E11D07A6C9005F35D8 /* RCTPropsAnimatedNode.m */; };
|
||||
|
@ -27,7 +26,6 @@
|
|||
2D3B5EF61D9B0B4800451313 /* RCTDiffClampAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 193F64F31D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m */; };
|
||||
2D3B5EF71D9B0B4800451313 /* RCTAdditionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501D71D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m */; };
|
||||
2D3B5EF81D9B0B4800451313 /* RCTAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501D91D07A6C9005F35D8 /* RCTAnimatedNode.m */; };
|
||||
2D3B5EF91D9B0B4800451313 /* RCTAnimationDriverNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DB1D07A6C9005F35D8 /* RCTAnimationDriverNode.m */; };
|
||||
2D3B5EFA1D9B0B4800451313 /* RCTInterpolationAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DD1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m */; };
|
||||
2D3B5EFB1D9B0B4800451313 /* RCTModuloAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 94DAE3F81D7334A70059942F /* RCTModuloAnimatedNode.m */; };
|
||||
2D3B5EFC1D9B0B4800451313 /* RCTMultiplicationAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DF1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.m */; };
|
||||
|
@ -36,6 +34,10 @@
|
|||
2D3B5EFF1D9B0B4800451313 /* RCTTransformAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E51D07A6C9005F35D8 /* RCTTransformAnimatedNode.m */; };
|
||||
2D3B5F001D9B0B4800451313 /* RCTValueAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E71D07A6C9005F35D8 /* RCTValueAnimatedNode.m */; };
|
||||
5C9894951D999639008027DB /* RCTDivisionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C9894941D999639008027DB /* RCTDivisionAnimatedNode.m */; };
|
||||
944244D01DB962DA0032A02B /* RCTFrameAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 94C1294D1D4069170025F25C /* RCTFrameAnimation.m */; };
|
||||
944244D11DB962DC0032A02B /* RCTSpringAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 94C1294F1D4069170025F25C /* RCTSpringAnimation.m */; };
|
||||
94C129511D40692B0025F25C /* RCTFrameAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 94C1294D1D4069170025F25C /* RCTFrameAnimation.m */; };
|
||||
94C129521D40692B0025F25C /* RCTSpringAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 94C1294F1D4069170025F25C /* RCTSpringAnimation.m */; };
|
||||
94DAE3F91D7334A70059942F /* RCTModuloAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 94DAE3F81D7334A70059942F /* RCTModuloAnimatedNode.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
|
@ -72,8 +74,6 @@
|
|||
13E501D71D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAdditionAnimatedNode.m; sourceTree = "<group>"; };
|
||||
13E501D81D07A6C9005F35D8 /* RCTAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimatedNode.h; sourceTree = "<group>"; };
|
||||
13E501D91D07A6C9005F35D8 /* RCTAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAnimatedNode.m; sourceTree = "<group>"; };
|
||||
13E501DA1D07A6C9005F35D8 /* RCTAnimationDriverNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimationDriverNode.h; sourceTree = "<group>"; };
|
||||
13E501DB1D07A6C9005F35D8 /* RCTAnimationDriverNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAnimationDriverNode.m; sourceTree = "<group>"; };
|
||||
13E501DC1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTInterpolationAnimatedNode.h; sourceTree = "<group>"; };
|
||||
13E501DD1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTInterpolationAnimatedNode.m; sourceTree = "<group>"; };
|
||||
13E501DE1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMultiplicationAnimatedNode.h; sourceTree = "<group>"; };
|
||||
|
@ -91,6 +91,11 @@
|
|||
2D2A28201D9B03D100D4039D /* libRCTAnimation-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTAnimation-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5C9894931D999639008027DB /* RCTDivisionAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDivisionAnimatedNode.h; sourceTree = "<group>"; };
|
||||
5C9894941D999639008027DB /* RCTDivisionAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDivisionAnimatedNode.m; sourceTree = "<group>"; };
|
||||
94C1294A1D4069170025F25C /* RCTAnimationDriver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTAnimationDriver.h; sourceTree = "<group>"; };
|
||||
94C1294C1D4069170025F25C /* RCTFrameAnimation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTFrameAnimation.h; sourceTree = "<group>"; };
|
||||
94C1294D1D4069170025F25C /* RCTFrameAnimation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTFrameAnimation.m; sourceTree = "<group>"; };
|
||||
94C1294E1D4069170025F25C /* RCTSpringAnimation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTSpringAnimation.h; sourceTree = "<group>"; };
|
||||
94C1294F1D4069170025F25C /* RCTSpringAnimation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTSpringAnimation.m; sourceTree = "<group>"; };
|
||||
94DAE3F71D7334A70059942F /* RCTModuloAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModuloAnimatedNode.h; sourceTree = "<group>"; };
|
||||
94DAE3F81D7334A70059942F /* RCTModuloAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuloAnimatedNode.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
@ -132,8 +137,6 @@
|
|||
13E501D71D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m */,
|
||||
13E501D81D07A6C9005F35D8 /* RCTAnimatedNode.h */,
|
||||
13E501D91D07A6C9005F35D8 /* RCTAnimatedNode.m */,
|
||||
13E501DA1D07A6C9005F35D8 /* RCTAnimationDriverNode.h */,
|
||||
13E501DB1D07A6C9005F35D8 /* RCTAnimationDriverNode.m */,
|
||||
13E501DC1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.h */,
|
||||
13E501DD1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m */,
|
||||
94DAE3F71D7334A70059942F /* RCTModuloAnimatedNode.h */,
|
||||
|
@ -161,12 +164,25 @@
|
|||
13E501C81D07A644005F35D8 /* RCTViewPropertyMapper.m */,
|
||||
13E501BD1D07A644005F35D8 /* RCTNativeAnimatedModule.h */,
|
||||
13E501BE1D07A644005F35D8 /* RCTNativeAnimatedModule.m */,
|
||||
94C129491D4069170025F25C /* Drivers */,
|
||||
13E501D51D07A6C9005F35D8 /* Nodes */,
|
||||
134814211AA4EA7D00B7C361 /* Products */,
|
||||
2D2A28201D9B03D100D4039D /* libRCTAnimation-tvOS.a */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94C129491D4069170025F25C /* Drivers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94C1294A1D4069170025F25C /* RCTAnimationDriver.h */,
|
||||
94C1294C1D4069170025F25C /* RCTFrameAnimation.h */,
|
||||
94C1294D1D4069170025F25C /* RCTFrameAnimation.m */,
|
||||
94C1294E1D4069170025F25C /* RCTSpringAnimation.h */,
|
||||
94C1294F1D4069170025F25C /* RCTSpringAnimation.m */,
|
||||
);
|
||||
path = Drivers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
@ -255,11 +271,12 @@
|
|||
2D3B5EF81D9B0B4800451313 /* RCTAnimatedNode.m in Sources */,
|
||||
2D3B5EFE1D9B0B4800451313 /* RCTStyleAnimatedNode.m in Sources */,
|
||||
2D3B5EFA1D9B0B4800451313 /* RCTInterpolationAnimatedNode.m in Sources */,
|
||||
2D3B5EF91D9B0B4800451313 /* RCTAnimationDriverNode.m in Sources */,
|
||||
2D3B5EFF1D9B0B4800451313 /* RCTTransformAnimatedNode.m in Sources */,
|
||||
2D3B5EFC1D9B0B4800451313 /* RCTMultiplicationAnimatedNode.m in Sources */,
|
||||
2D3B5EFD1D9B0B4800451313 /* RCTPropsAnimatedNode.m in Sources */,
|
||||
2D3B5EF31D9B0B3400451313 /* RCTViewPropertyMapper.m in Sources */,
|
||||
944244D01DB962DA0032A02B /* RCTFrameAnimation.m in Sources */,
|
||||
944244D11DB962DC0032A02B /* RCTSpringAnimation.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -267,6 +284,8 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
94C129511D40692B0025F25C /* RCTFrameAnimation.m in Sources */,
|
||||
94C129521D40692B0025F25C /* RCTSpringAnimation.m in Sources */,
|
||||
13E501F01D07A6C9005F35D8 /* RCTValueAnimatedNode.m in Sources */,
|
||||
94DAE3F91D7334A70059942F /* RCTModuloAnimatedNode.m in Sources */,
|
||||
193F64F41D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m in Sources */,
|
||||
|
@ -279,7 +298,6 @@
|
|||
13E501EB1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m in Sources */,
|
||||
13E501E81D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m in Sources */,
|
||||
5C9894951D999639008027DB /* RCTDivisionAnimatedNode.m in Sources */,
|
||||
13E501EA1D07A6C9005F35D8 /* RCTAnimationDriverNode.m in Sources */,
|
||||
13E501EF1D07A6C9005F35D8 /* RCTTransformAnimatedNode.m in Sources */,
|
||||
13E501D41D07A644005F35D8 /* RCTViewPropertyMapper.m in Sources */,
|
||||
);
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
#import "RCTNativeAnimatedModule.h"
|
||||
|
||||
#import "RCTAdditionAnimatedNode.h"
|
||||
#import "RCTAnimationDriverNode.h"
|
||||
#import "RCTAnimationDriver.h"
|
||||
#import "RCTFrameAnimation.h"
|
||||
#import "RCTSpringAnimation.h"
|
||||
#import "RCTAnimationUtils.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
|
@ -27,9 +29,9 @@
|
|||
@implementation RCTNativeAnimatedModule
|
||||
{
|
||||
NSMutableDictionary<NSNumber *, RCTAnimatedNode *> *_animationNodes;
|
||||
NSMutableDictionary<NSNumber *, RCTAnimationDriverNode *> *_animationDrivers;
|
||||
NSMutableSet<RCTAnimationDriverNode *> *_activeAnimations;
|
||||
NSMutableSet<RCTAnimationDriverNode *> *_finishedAnimations;
|
||||
NSMutableDictionary<NSNumber *, id<RCTAnimationDriver>> *_animationDrivers;
|
||||
NSMutableSet<id<RCTAnimationDriver>> *_activeAnimations;
|
||||
NSMutableSet<id<RCTAnimationDriver>> *_finishedAnimations;
|
||||
NSMutableSet<RCTValueAnimatedNode *> *_updatedValueNodes;
|
||||
NSMutableSet<RCTPropsAnimatedNode *> *_propAnimationNodes;
|
||||
CADisplayLink *_displayLink;
|
||||
|
@ -87,6 +89,7 @@ RCT_EXPORT_METHOD(createAnimatedNode:(nonnull NSNumber *)tag
|
|||
}
|
||||
|
||||
RCTAnimatedNode *node = [[nodeClass alloc] initWithTag:tag config:config];
|
||||
|
||||
_animationNodes[tag] = node;
|
||||
|
||||
if ([node isKindOfClass:[RCTPropsAnimatedNode class]]) {
|
||||
|
@ -129,24 +132,28 @@ RCT_EXPORT_METHOD(startAnimatingNode:(nonnull NSNumber *)animationId
|
|||
config:(NSDictionary<NSString *, id> *)config
|
||||
endCallback:(RCTResponseSenderBlock)callBack)
|
||||
{
|
||||
if (RCT_DEBUG && ![config[@"type"] isEqual:@"frames"]) {
|
||||
RCTValueAnimatedNode *valueNode = (RCTValueAnimatedNode *)_animationNodes[nodeTag];
|
||||
|
||||
NSString *type = config[@"type"];
|
||||
id<RCTAnimationDriver>animationDriver;
|
||||
|
||||
if ([type isEqual:@"frames"]) {
|
||||
animationDriver = [[RCTFrameAnimation alloc] initWithId:animationId
|
||||
config:config
|
||||
forNode:valueNode
|
||||
callBack:callBack];
|
||||
|
||||
} else if ([type isEqual:@"spring"]) {
|
||||
animationDriver = [[RCTSpringAnimation alloc] initWithId:animationId
|
||||
config:config
|
||||
forNode:valueNode
|
||||
callBack:callBack];
|
||||
|
||||
} else {
|
||||
RCTLogError(@"Unsupported animation type: %@", config[@"type"]);
|
||||
return;
|
||||
}
|
||||
|
||||
NSTimeInterval delay = [RCTConvert double:config[@"delay"]];
|
||||
NSNumber *toValue = [RCTConvert NSNumber:config[@"toValue"]] ?: @1;
|
||||
NSArray<NSNumber *> *frames = [RCTConvert NSNumberArray:config[@"frames"]];
|
||||
|
||||
RCTValueAnimatedNode *valueNode = (RCTValueAnimatedNode *)_animationNodes[nodeTag];
|
||||
|
||||
RCTAnimationDriverNode *animationDriver =
|
||||
[[RCTAnimationDriverNode alloc] initWithId:animationId
|
||||
delay:delay
|
||||
toValue:toValue.doubleValue
|
||||
frames:frames
|
||||
forNode:valueNode
|
||||
callBack:callBack];
|
||||
[_activeAnimations addObject:animationDriver];
|
||||
_animationDrivers[animationId] = animationDriver;
|
||||
[animationDriver startAnimation];
|
||||
|
@ -155,7 +162,7 @@ RCT_EXPORT_METHOD(startAnimatingNode:(nonnull NSNumber *)animationId
|
|||
|
||||
RCT_EXPORT_METHOD(stopAnimation:(nonnull NSNumber *)animationId)
|
||||
{
|
||||
RCTAnimationDriverNode *driver = _animationDrivers[animationId];
|
||||
id<RCTAnimationDriver>driver = _animationDrivers[animationId];
|
||||
if (driver) {
|
||||
[driver removeAnimation];
|
||||
[_animationDrivers removeObjectForKey:animationId];
|
||||
|
@ -172,6 +179,7 @@ RCT_EXPORT_METHOD(setAnimatedNodeValue:(nonnull NSNumber *)nodeTag
|
|||
RCTLogError(@"Not a value node.");
|
||||
return;
|
||||
}
|
||||
|
||||
RCTValueAnimatedNode *valueNode = (RCTValueAnimatedNode *)node;
|
||||
valueNode.value = value.floatValue;
|
||||
[valueNode setNeedsUpdate];
|
||||
|
@ -272,7 +280,7 @@ RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag)
|
|||
{
|
||||
// Step Current active animations
|
||||
// This also recursively marks children nodes as needing update
|
||||
for (RCTAnimationDriverNode *animationDriver in _activeAnimations) {
|
||||
for (id<RCTAnimationDriver>animationDriver in _activeAnimations) {
|
||||
[animationDriver stepAnimation];
|
||||
}
|
||||
|
||||
|
@ -283,7 +291,7 @@ RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag)
|
|||
}
|
||||
|
||||
// Cleanup nodes and prepare for next cycle. Remove updated nodes from bucket.
|
||||
for (RCTAnimationDriverNode *driverNode in _activeAnimations) {
|
||||
for (id<RCTAnimationDriver>driverNode in _activeAnimations) {
|
||||
[driverNode cleanupAnimationUpdate];
|
||||
}
|
||||
for (RCTValueAnimatedNode *valueNode in _updatedValueNodes) {
|
||||
|
@ -291,13 +299,13 @@ RCT_EXPORT_METHOD(stopListeningToAnimatedNodeValue:(nonnull NSNumber *)tag)
|
|||
}
|
||||
[_updatedValueNodes removeAllObjects];
|
||||
|
||||
for (RCTAnimationDriverNode *driverNode in _activeAnimations) {
|
||||
for (id<RCTAnimationDriver>driverNode in _activeAnimations) {
|
||||
if (driverNode.animationHasFinished) {
|
||||
[driverNode removeAnimation];
|
||||
[_finishedAnimations addObject:driverNode];
|
||||
}
|
||||
}
|
||||
for (RCTAnimationDriverNode *driverNode in _finishedAnimations) {
|
||||
for (id<RCTAnimationDriver>driverNode in _finishedAnimations) {
|
||||
[_activeAnimations removeObject:driverNode];
|
||||
[_animationDrivers removeObjectForKey:driverNode.animationId];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue