diff --git a/Libraries/NativeAnimation/Drivers/RCTDecayAnimation.m b/Libraries/NativeAnimation/Drivers/RCTDecayAnimation.m index 9b3b90e75a..27d4edfc3b 100644 --- a/Libraries/NativeAnimation/Drivers/RCTDecayAnimation.m +++ b/Libraries/NativeAnimation/Drivers/RCTDecayAnimation.m @@ -10,6 +10,7 @@ #import #import +#import "RCTAnimationUtils.h" #import "RCTValueAnimatedNode.h" @interface RCTDecayAnimation () @@ -100,7 +101,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) CGFloat value = _fromValue + (_velocity / (1 - _deceleration)) * - (1 - exp(-(1 - _deceleration) * (currentTime - _frameStartTime) * 1000.0)); + (1 - exp(-(1 - _deceleration) * (currentTime - _frameStartTime) * 1000.0 / RCTAnimationDragCoefficient())); [self updateValue:value]; diff --git a/Libraries/NativeAnimation/Drivers/RCTFrameAnimation.m b/Libraries/NativeAnimation/Drivers/RCTFrameAnimation.m index c03d4be341..a6dfde5001 100644 --- a/Libraries/NativeAnimation/Drivers/RCTFrameAnimation.m +++ b/Libraries/NativeAnimation/Drivers/RCTFrameAnimation.m @@ -97,7 +97,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) } _animationCurrentTime = currentTime; - NSTimeInterval currentDuration = _animationCurrentTime - _animationStartTime; + NSTimeInterval currentDuration = (_animationCurrentTime - _animationStartTime) / RCTAnimationDragCoefficient(); // Determine how many frames have passed since last update. // Get index of frames that surround the current interval diff --git a/Libraries/NativeAnimation/Drivers/RCTSpringAnimation.m b/Libraries/NativeAnimation/Drivers/RCTSpringAnimation.m index 926e33b37e..b7e784b6ce 100644 --- a/Libraries/NativeAnimation/Drivers/RCTSpringAnimation.m +++ b/Libraries/NativeAnimation/Drivers/RCTSpringAnimation.m @@ -12,6 +12,7 @@ #import #import +#import "RCTAnimationUtils.h" #import "RCTValueAnimatedNode.h" @interface RCTSpringAnimation () @@ -45,7 +46,7 @@ const NSTimeInterval MAX_DELTA_TIME = 0.064; NSInteger _iterations; NSInteger _currentLoop; - + NSTimeInterval _t; // Current time (startTime + dt) } @@ -110,7 +111,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) // Animation has not begun or animation has already finished. return; } - + // calculate delta time NSTimeInterval deltaTime; if(_animationStartTime == -1) { @@ -120,22 +121,22 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) } else { // Handle frame drops, and only advance dt by a max of MAX_DELTA_TIME deltaTime = MIN(MAX_DELTA_TIME, currentTime - _animationCurrentTime); - _t = _t + deltaTime; + _t = _t + deltaTime / RCTAnimationDragCoefficient(); } - + // store the timestamp _animationCurrentTime = currentTime; - + CGFloat c = _damping; CGFloat m = _mass; CGFloat k = _stiffness; CGFloat v0 = -_initialVelocity; - + CGFloat zeta = c / (2 * sqrtf(k * m)); CGFloat omega0 = sqrtf(k / m); CGFloat omega1 = omega0 * sqrtf(1.0 - (zeta * zeta)); CGFloat x0 = _toValue - _fromValue; - + CGFloat position; CGFloat velocity; if (zeta < 1) { @@ -163,12 +164,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) velocity = envelope * (v0 * (_t * omega0 - 1) + _t * x0 * (omega0 * omega0)); } - + _lastPosition = position; _lastVelocity = velocity; - + [self onUpdate:position]; - + // Conditions for stopping the spring animation BOOL isOvershooting = NO; if (_overshootClamping && _stiffness != 0) { @@ -183,7 +184,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) if (_stiffness != 0) { isDisplacement = ABS(_toValue - position) <= _restDisplacementThreshold; } - + if (isOvershooting || (isVelocity && isDisplacement)) { if (_stiffness != 0) { // Ensure that we end up with a round value @@ -192,7 +193,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) } [self onUpdate:_toValue]; } - + if (_iterations == -1 || _currentLoop < _iterations) { _lastPosition = _fromValue; _lastVelocity = _initialVelocity; diff --git a/Libraries/NativeAnimation/RCTAnimationUtils.h b/Libraries/NativeAnimation/RCTAnimationUtils.h index b5f766a588..39f2fe470b 100644 --- a/Libraries/NativeAnimation/RCTAnimationUtils.h +++ b/Libraries/NativeAnimation/RCTAnimationUtils.h @@ -30,3 +30,9 @@ RCT_EXTERN CGFloat RCTInterpolateValue(CGFloat value, RCT_EXTERN CGFloat RCTRadiansToDegrees(CGFloat radians); RCT_EXTERN CGFloat RCTDegreesToRadians(CGFloat degrees); + +/** + * Coefficient to slow down animations, respects the ios + * simulator `Slow Animations (⌘T)` option. + */ +RCT_EXTERN CGFloat RCTAnimationDragCoefficient(void); diff --git a/Libraries/NativeAnimation/RCTAnimationUtils.m b/Libraries/NativeAnimation/RCTAnimationUtils.m index a7868f3c88..7ffb4690d2 100644 --- a/Libraries/NativeAnimation/RCTAnimationUtils.m +++ b/Libraries/NativeAnimation/RCTAnimationUtils.m @@ -93,3 +93,17 @@ CGFloat RCTDegreesToRadians(CGFloat degrees) { return degrees / 180.0 * M_PI; } + +#if TARGET_IPHONE_SIMULATOR +// Based on https://stackoverflow.com/a/13307674 +float UIAnimationDragCoefficient(void); +#endif + +CGFloat RCTAnimationDragCoefficient() +{ +#if TARGET_IPHONE_SIMULATOR + return (CGFloat)UIAnimationDragCoefficient(); +#else + return 1.0; +#endif +}