Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Native Animated] Support for animated tracking in native driver #17896

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions Libraries/Animated/src/nodes/AnimatedTracking.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

const AnimatedValue = require('./AnimatedValue');
const AnimatedNode = require('./AnimatedNode');
const {
generateNewAnimationId,
shouldUseNativeDriver,
} = require('../NativeAnimatedHelper');

import type {EndCallback} from '../animations/Animation';

Expand All @@ -23,6 +27,7 @@ class AnimatedTracking extends AnimatedNode {
_callback: ?EndCallback;
_animationConfig: Object;
_animationClass: any;
_useNativeDriver: boolean;

constructor(
value: AnimatedValue,
Expand All @@ -36,16 +41,32 @@ class AnimatedTracking extends AnimatedNode {
this._parent = parent;
this._animationClass = animationClass;
this._animationConfig = animationConfig;
this._useNativeDriver = shouldUseNativeDriver(animationConfig);
this._callback = callback;
this.__attach();
}

__makeNative() {
this.__isNative = true;
this._parent.__makeNative();
super.__makeNative();
this._value.__makeNative();
}

__getValue(): Object {
return this._parent.__getValue();
}

__attach(): void {
this._parent.__addChild(this);
if (this._useNativeDriver) {
// when the tracking starts we need to convert this node to a "native node"
// so that the parent node will be made "native" too. This is necessary as
// if we don't do this `update` method will get called. At that point it
// may be too late as it would mean the JS driver has already started
// updating node values
this.__makeNative();
}
}

__detach(): void {
Expand All @@ -62,6 +83,22 @@ class AnimatedTracking extends AnimatedNode {
this._callback,
);
}

__getNativeConfig(): any {
const animation = new this._animationClass({
...this._animationConfig,
// remove toValue from the config as it's a ref to Animated.Value
toValue: undefined,
});
const animationConfig = animation.__getNativeAnimationConfig();
return {
type: 'tracking',
animationId: generateNewAnimationId(),
animationConfig,
toValue: this._parent.__getNativeTag(),
value: this._value.__getNativeTag(),
};
}
}

module.exports = AnimatedTracking;
5 changes: 3 additions & 2 deletions Libraries/Animated/src/nodes/AnimatedValue.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const NativeAnimatedHelper = require('../NativeAnimatedHelper');

import type Animation, {EndCallback} from '../animations/Animation';
import type {InterpolationConfigType} from './AnimatedInterpolation';
import type AnimatedTracking from './AnimatedTracking';

const NativeAnimatedAPI = NativeAnimatedHelper.API;

Expand Down Expand Up @@ -76,7 +77,7 @@ class AnimatedValue extends AnimatedWithChildren {
_startingValue: number;
_offset: number;
_animation: ?Animation;
_tracking: ?AnimatedNode;
_tracking: ?AnimatedTracking;
_listeners: {[key: string]: ValueListenerCallback};
__nativeAnimatedValueListener: ?any;

Expand Down Expand Up @@ -311,7 +312,7 @@ class AnimatedValue extends AnimatedWithChildren {
/**
* Typically only used internally.
*/
track(tracking: AnimatedNode): void {
track(tracking: AnimatedTracking): void {
this.stopTracking();
this._tracking = tracking;
}
Expand Down
1 change: 1 addition & 0 deletions Libraries/NativeAnimation/Drivers/RCTAnimationDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)startAnimation;
- (void)stepAnimationWithTime:(NSTimeInterval)currentTime;
- (void)stopAnimation;
- (void)resetAnimationConfig:(NSDictionary *)config;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we call this updateAnimationConfig instead since it doesn't "reset" the animation completely but only updates certain parameters.


NS_ASSUME_NONNULL_END

Expand Down
23 changes: 14 additions & 9 deletions Libraries/NativeAnimation/Drivers/RCTDecayAnimation.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,27 @@ - (instancetype)initWithId:(NSNumber *)animationId
callBack:(nullable RCTResponseSenderBlock)callback;
{
if ((self = [super init])) {
NSNumber *iterations = [RCTConvert NSNumber:config[@"iterations"]] ?: @1;

_callback = [callback copy];
_animationId = animationId;
_valueNode = valueNode;
_fromValue = 0;
_lastValue = 0;
_valueNode = valueNode;
_callback = [callback copy];
_velocity = [RCTConvert CGFloat:config[@"velocity"]];
_deceleration = [RCTConvert CGFloat:config[@"deceleration"]];
_iterations = iterations.integerValue;
_currentLoop = 1;
_animationHasFinished = iterations.integerValue == 0;
_velocity = [RCTConvert CGFloat:config[@"velocity"]]; // initial velocity
[self resetAnimationConfig:config];
}
return self;
}

- (void)resetAnimationConfig:(NSDictionary *)config
{
NSNumber *iterations = [RCTConvert NSNumber:config[@"iterations"]] ?: @1;
_fromValue = _lastValue;
_deceleration = [RCTConvert CGFloat:config[@"deceleration"]];
_iterations = iterations.integerValue;
_currentLoop = 1;
_animationHasFinished = iterations.integerValue == 0;
}

RCT_NOT_IMPLEMENTED(- (instancetype)init)

- (void)startAnimation
Expand Down
29 changes: 19 additions & 10 deletions Libraries/NativeAnimation/Drivers/RCTFrameAnimation.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ @implementation RCTFrameAnimation
NSArray<NSNumber *> *_frames;
CGFloat _toValue;
CGFloat _fromValue;
CGFloat _lastPosition;
NSTimeInterval _animationStartTime;
NSTimeInterval _animationCurrentTime;
RCTResponseSenderBlock _callback;
Expand All @@ -44,23 +45,30 @@ - (instancetype)initWithId:(NSNumber *)animationId
callBack:(nullable RCTResponseSenderBlock)callback;
{
if ((self = [super init])) {
NSNumber *toValue = [RCTConvert NSNumber:config[@"toValue"]] ?: @1;
NSArray<NSNumber *> *frames = [RCTConvert NSNumberArray:config[@"frames"]];
NSNumber *iterations = [RCTConvert NSNumber:config[@"iterations"]] ?: @1;

_animationId = animationId;
_toValue = toValue.floatValue;
_fromValue = valueNode.value;
_lastPosition = _fromValue = valueNode.value;
_valueNode = valueNode;
_frames = [frames copy];
_callback = [callback copy];
_animationHasFinished = iterations.integerValue == 0;
_iterations = iterations.integerValue;
_currentLoop = 1;
[self resetAnimationConfig:config];
}
return self;
}

- (void)resetAnimationConfig:(NSDictionary *)config
{
NSNumber *toValue = [RCTConvert NSNumber:config[@"toValue"]] ?: @1;
NSArray<NSNumber *> *frames = [RCTConvert NSNumberArray:config[@"frames"]];
NSNumber *iterations = [RCTConvert NSNumber:config[@"iterations"]] ?: @1;

_fromValue = _lastPosition;
_toValue = toValue.floatValue;
_frames = [frames copy];
_animationStartTime = _animationCurrentTime = -1;
_animationHasFinished = iterations.integerValue == 0;
_iterations = iterations.integerValue;
_currentLoop = 1;
}

RCT_NOT_IMPLEMENTED(- (instancetype)init)

- (void)startAnimation
Expand Down Expand Up @@ -144,6 +152,7 @@ - (void)updateOutputWithFrameOutput:(CGFloat)frameOutput
EXTRAPOLATE_TYPE_EXTEND,
EXTRAPOLATE_TYPE_EXTEND);

_lastPosition = outputValue;
_valueNode.value = outputValue;
[_valueNode setNeedsUpdate];
}
Expand Down
44 changes: 24 additions & 20 deletions Libraries/NativeAnimation/Drivers/RCTSpringAnimation.m
Original file line number Diff line number Diff line change
Expand Up @@ -57,33 +57,37 @@ - (instancetype)initWithId:(NSNumber *)animationId
callBack:(nullable RCTResponseSenderBlock)callback
{
if ((self = [super init])) {
NSNumber *iterations = [RCTConvert NSNumber:config[@"iterations"]] ?: @1;

_animationId = animationId;
_toValue = [RCTConvert CGFloat:config[@"toValue"]];
_fromValue = valueNode.value;
_lastPosition = 0;
_lastPosition = valueNode.value;
_valueNode = valueNode;
_overshootClamping = [RCTConvert BOOL:config[@"overshootClamping"]];
_restDisplacementThreshold = [RCTConvert CGFloat:config[@"restDisplacementThreshold"]];
_restSpeedThreshold = [RCTConvert CGFloat:config[@"restSpeedThreshold"]];
_stiffness = [RCTConvert CGFloat:config[@"stiffness"]];
_damping = [RCTConvert CGFloat:config[@"damping"]];
_mass = [RCTConvert CGFloat:config[@"mass"]];
_initialVelocity = [RCTConvert CGFloat:config[@"initialVelocity"]];

_lastVelocity = [RCTConvert CGFloat:config[@"initialVelocity"]];
_callback = [callback copy];

_lastPosition = _fromValue;
_lastVelocity = _initialVelocity;

_animationHasFinished = iterations.integerValue == 0;
_iterations = iterations.integerValue;
_currentLoop = 1;
[self resetAnimationConfig:config];
}
return self;
}

- (void)resetAnimationConfig:(NSDictionary *)config
{
NSNumber *iterations = [RCTConvert NSNumber:config[@"iterations"]] ?: @1;
_toValue = [RCTConvert CGFloat:config[@"toValue"]];
_overshootClamping = [RCTConvert BOOL:config[@"overshootClamping"]];
_restDisplacementThreshold = [RCTConvert CGFloat:config[@"restDisplacementThreshold"]];
_restSpeedThreshold = [RCTConvert CGFloat:config[@"restSpeedThreshold"]];
_stiffness = [RCTConvert CGFloat:config[@"stiffness"]];
_damping = [RCTConvert CGFloat:config[@"damping"]];
_mass = [RCTConvert CGFloat:config[@"mass"]];
_initialVelocity = _lastVelocity;
_fromValue = _lastPosition;
_fromValue = _lastPosition;
_lastVelocity = _initialVelocity;
_animationHasFinished = iterations.integerValue == 0;
_iterations = iterations.integerValue;
_currentLoop = 1;
_animationStartTime = _animationCurrentTime = -1;
_animationHasBegun = YES;
}

RCT_NOT_IMPLEMENTED(- (instancetype)init)

- (void)startAnimation
Expand Down
3 changes: 3 additions & 0 deletions Libraries/NativeAnimation/Nodes/RCTAnimatedNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@

#import <Foundation/Foundation.h>

@class RCTNativeAnimatedNodesManager;

@interface RCTAnimatedNode : NSObject

- (instancetype)initWithTag:(NSNumber *)tag
config:(NSDictionary<NSString *, id> *)config NS_DESIGNATED_INITIALIZER;

@property (nonatomic, readonly) NSNumber *nodeTag;
@property (nonatomic, weak) RCTNativeAnimatedNodesManager *manager;
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id> *config;

@property (nonatomic, copy, readonly) NSMapTable<NSNumber *, RCTAnimatedNode *> *childNodes;
Expand Down
15 changes: 15 additions & 0 deletions Libraries/NativeAnimation/Nodes/RCTTrackingAnimatedNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* 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 "RCTAnimatedNode.h"


@interface RCTTrackingAnimatedNode : RCTAnimatedNode

@end
54 changes: 54 additions & 0 deletions Libraries/NativeAnimation/Nodes/RCTTrackingAnimatedNode.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* 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 "RCTTrackingAnimatedNode.h"
#import "RCTValueAnimatedNode.h"
#import "RCTNativeAnimatedNodesManager.h"

@implementation RCTTrackingAnimatedNode {
NSNumber *_animationId;
NSNumber *_toValueNodeTag;
NSNumber *_valueNodeTag;
NSMutableDictionary *_animationConfig;
}

- (instancetype)initWithTag:(NSNumber *)tag
config:(NSDictionary<NSString *, id> *)config
{
if ((self = [super initWithTag:tag config:config])) {
_animationId = config[@"animationId"];
_toValueNodeTag = config[@"toValue"];
_valueNodeTag = config[@"value"];
_animationConfig = [NSMutableDictionary dictionaryWithDictionary:config[@"animationConfig"]];
}
return self;
}

- (void)onDetachedFromNode:(RCTAnimatedNode *)parent
{
[self.manager stopAnimation:_animationId];
[super onDetachedFromNode:parent];
}

- (void)performUpdate
{
[super performUpdate];

// change animation config's "toValue" to reflect updated value of the parent node
RCTValueAnimatedNode *node = (RCTValueAnimatedNode *)[self.parentNodes objectForKey:_toValueNodeTag];
_animationConfig[@"toValue"] = @(node.value);

[self.manager startAnimatingNode:_animationId
nodeTag:_valueNodeTag
config:_animationConfig
endCallback:nil];
}

@end

Loading