mirror of
https://github.com/status-im/react-native.git
synced 2025-02-10 08:26:23 +00:00
Support the Slow Animations
option of the iOS simulator (#21157)
Summary: RN animations currently ignore the `Slow Animations` option on the iOS simulator because we don't use UIKit animations directly. This uses a private api to get the slow coefficient and use it in the native animated driver. We only compile the private api code on simulator so this won't cause issues for app store approval. One possible issue is that the api changes in new iOS versions but I think it's reasonable to do this. Note that this won't work with JS driven animations, we could expose the slow coefficient as a constant and use that in JS but I decided not to implement it. Pull Request resolved: https://github.com/facebook/react-native/pull/21157 Differential Revision: D9980306 Pulled By: sahrens fbshipit-source-id: bdbce2e469261a75cb4b9a251e8e8f212bb9c4e7
This commit is contained in:
parent
a6f47d46ca
commit
40bcc38d91
@ -10,6 +10,7 @@
|
|||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
#import <React/RCTConvert.h>
|
#import <React/RCTConvert.h>
|
||||||
|
|
||||||
|
#import "RCTAnimationUtils.h"
|
||||||
#import "RCTValueAnimatedNode.h"
|
#import "RCTValueAnimatedNode.h"
|
||||||
|
|
||||||
@interface RCTDecayAnimation ()
|
@interface RCTDecayAnimation ()
|
||||||
@ -100,7 +101,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||||||
|
|
||||||
CGFloat value = _fromValue +
|
CGFloat value = _fromValue +
|
||||||
(_velocity / (1 - _deceleration)) *
|
(_velocity / (1 - _deceleration)) *
|
||||||
(1 - exp(-(1 - _deceleration) * (currentTime - _frameStartTime) * 1000.0));
|
(1 - exp(-(1 - _deceleration) * (currentTime - _frameStartTime) * 1000.0 / RCTAnimationDragCoefficient()));
|
||||||
|
|
||||||
[self updateValue:value];
|
[self updateValue:value];
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_animationCurrentTime = currentTime;
|
_animationCurrentTime = currentTime;
|
||||||
NSTimeInterval currentDuration = _animationCurrentTime - _animationStartTime;
|
NSTimeInterval currentDuration = (_animationCurrentTime - _animationStartTime) / RCTAnimationDragCoefficient();
|
||||||
|
|
||||||
// Determine how many frames have passed since last update.
|
// Determine how many frames have passed since last update.
|
||||||
// Get index of frames that surround the current interval
|
// Get index of frames that surround the current interval
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#import <React/RCTConvert.h>
|
#import <React/RCTConvert.h>
|
||||||
#import <React/RCTDefines.h>
|
#import <React/RCTDefines.h>
|
||||||
|
|
||||||
|
#import "RCTAnimationUtils.h"
|
||||||
#import "RCTValueAnimatedNode.h"
|
#import "RCTValueAnimatedNode.h"
|
||||||
|
|
||||||
@interface RCTSpringAnimation ()
|
@interface RCTSpringAnimation ()
|
||||||
@ -45,7 +46,7 @@ const NSTimeInterval MAX_DELTA_TIME = 0.064;
|
|||||||
|
|
||||||
NSInteger _iterations;
|
NSInteger _iterations;
|
||||||
NSInteger _currentLoop;
|
NSInteger _currentLoop;
|
||||||
|
|
||||||
NSTimeInterval _t; // Current time (startTime + dt)
|
NSTimeInterval _t; // Current time (startTime + dt)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +111,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||||||
// Animation has not begun or animation has already finished.
|
// Animation has not begun or animation has already finished.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate delta time
|
// calculate delta time
|
||||||
NSTimeInterval deltaTime;
|
NSTimeInterval deltaTime;
|
||||||
if(_animationStartTime == -1) {
|
if(_animationStartTime == -1) {
|
||||||
@ -120,22 +121,22 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||||||
} else {
|
} else {
|
||||||
// Handle frame drops, and only advance dt by a max of MAX_DELTA_TIME
|
// Handle frame drops, and only advance dt by a max of MAX_DELTA_TIME
|
||||||
deltaTime = MIN(MAX_DELTA_TIME, currentTime - _animationCurrentTime);
|
deltaTime = MIN(MAX_DELTA_TIME, currentTime - _animationCurrentTime);
|
||||||
_t = _t + deltaTime;
|
_t = _t + deltaTime / RCTAnimationDragCoefficient();
|
||||||
}
|
}
|
||||||
|
|
||||||
// store the timestamp
|
// store the timestamp
|
||||||
_animationCurrentTime = currentTime;
|
_animationCurrentTime = currentTime;
|
||||||
|
|
||||||
CGFloat c = _damping;
|
CGFloat c = _damping;
|
||||||
CGFloat m = _mass;
|
CGFloat m = _mass;
|
||||||
CGFloat k = _stiffness;
|
CGFloat k = _stiffness;
|
||||||
CGFloat v0 = -_initialVelocity;
|
CGFloat v0 = -_initialVelocity;
|
||||||
|
|
||||||
CGFloat zeta = c / (2 * sqrtf(k * m));
|
CGFloat zeta = c / (2 * sqrtf(k * m));
|
||||||
CGFloat omega0 = sqrtf(k / m);
|
CGFloat omega0 = sqrtf(k / m);
|
||||||
CGFloat omega1 = omega0 * sqrtf(1.0 - (zeta * zeta));
|
CGFloat omega1 = omega0 * sqrtf(1.0 - (zeta * zeta));
|
||||||
CGFloat x0 = _toValue - _fromValue;
|
CGFloat x0 = _toValue - _fromValue;
|
||||||
|
|
||||||
CGFloat position;
|
CGFloat position;
|
||||||
CGFloat velocity;
|
CGFloat velocity;
|
||||||
if (zeta < 1) {
|
if (zeta < 1) {
|
||||||
@ -163,12 +164,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||||||
velocity =
|
velocity =
|
||||||
envelope * (v0 * (_t * omega0 - 1) + _t * x0 * (omega0 * omega0));
|
envelope * (v0 * (_t * omega0 - 1) + _t * x0 * (omega0 * omega0));
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastPosition = position;
|
_lastPosition = position;
|
||||||
_lastVelocity = velocity;
|
_lastVelocity = velocity;
|
||||||
|
|
||||||
[self onUpdate:position];
|
[self onUpdate:position];
|
||||||
|
|
||||||
// Conditions for stopping the spring animation
|
// Conditions for stopping the spring animation
|
||||||
BOOL isOvershooting = NO;
|
BOOL isOvershooting = NO;
|
||||||
if (_overshootClamping && _stiffness != 0) {
|
if (_overshootClamping && _stiffness != 0) {
|
||||||
@ -183,7 +184,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||||||
if (_stiffness != 0) {
|
if (_stiffness != 0) {
|
||||||
isDisplacement = ABS(_toValue - position) <= _restDisplacementThreshold;
|
isDisplacement = ABS(_toValue - position) <= _restDisplacementThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOvershooting || (isVelocity && isDisplacement)) {
|
if (isOvershooting || (isVelocity && isDisplacement)) {
|
||||||
if (_stiffness != 0) {
|
if (_stiffness != 0) {
|
||||||
// Ensure that we end up with a round value
|
// Ensure that we end up with a round value
|
||||||
@ -192,7 +193,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||||||
}
|
}
|
||||||
[self onUpdate:_toValue];
|
[self onUpdate:_toValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_iterations == -1 || _currentLoop < _iterations) {
|
if (_iterations == -1 || _currentLoop < _iterations) {
|
||||||
_lastPosition = _fromValue;
|
_lastPosition = _fromValue;
|
||||||
_lastVelocity = _initialVelocity;
|
_lastVelocity = _initialVelocity;
|
||||||
|
@ -30,3 +30,9 @@ RCT_EXTERN CGFloat RCTInterpolateValue(CGFloat value,
|
|||||||
|
|
||||||
RCT_EXTERN CGFloat RCTRadiansToDegrees(CGFloat radians);
|
RCT_EXTERN CGFloat RCTRadiansToDegrees(CGFloat radians);
|
||||||
RCT_EXTERN CGFloat RCTDegreesToRadians(CGFloat degrees);
|
RCT_EXTERN CGFloat RCTDegreesToRadians(CGFloat degrees);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coefficient to slow down animations, respects the ios
|
||||||
|
* simulator `Slow Animations (⌘T)` option.
|
||||||
|
*/
|
||||||
|
RCT_EXTERN CGFloat RCTAnimationDragCoefficient(void);
|
||||||
|
@ -93,3 +93,17 @@ CGFloat RCTDegreesToRadians(CGFloat degrees)
|
|||||||
{
|
{
|
||||||
return degrees / 180.0 * M_PI;
|
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
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user