diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js index a1d43d2ee..b1d84d2a7 100644 --- a/Libraries/Animated/src/AnimatedImplementation.js +++ b/Libraries/Animated/src/AnimatedImplementation.js @@ -763,6 +763,18 @@ class AnimatedValue extends AnimatedWithChildren { } } + /** + * Sets the offset value to the base value, and resets the base value to zero. + * The final output of the value is unchanged. + */ + extractOffset(): void { + this._offset += this._value; + this._value = 0; + if (this.__isNative) { + NativeAnimatedAPI.extractAnimatedNodeOffset(this.__getNativeTag()); + } + } + /** * Adds an asynchronous listener to the value so you can observe updates from * animations. This is useful because there is no way to diff --git a/Libraries/Animated/src/NativeAnimatedHelper.js b/Libraries/Animated/src/NativeAnimatedHelper.js index 67aae660c..168451a47 100644 --- a/Libraries/Animated/src/NativeAnimatedHelper.js +++ b/Libraries/Animated/src/NativeAnimatedHelper.js @@ -73,6 +73,10 @@ const API = { assertNativeAnimatedModule(); NativeAnimatedModule.flattenAnimatedNodeOffset(nodeTag); }, + extractAnimatedNodeOffset: function(nodeTag: number): void { + assertNativeAnimatedModule(); + NativeAnimatedModule.extractAnimatedNodeOffset(nodeTag); + }, connectAnimatedNodeToView: function(nodeTag: number, viewTag: number): void { assertNativeAnimatedModule(); NativeAnimatedModule.connectAnimatedNodeToView(nodeTag, viewTag); diff --git a/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h b/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h index cffedb32d..fb0b28854 100644 --- a/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h +++ b/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h @@ -22,6 +22,7 @@ - (void)setOffset:(CGFloat)offset; - (void)flattenOffset; +- (void)extractOffset; @property (nonatomic, assign) CGFloat value; @property (nonatomic, weak) id valueObserver; diff --git a/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.m index 29d2a6c14..82eff7b62 100644 --- a/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.m +++ b/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.m @@ -35,6 +35,12 @@ _offset = 0; } +- (void)extractOffset +{ + _offset += _value; + _value = 0; +} + - (CGFloat)value { return _value + _offset; diff --git a/Libraries/NativeAnimation/RCTNativeAnimatedModule.m b/Libraries/NativeAnimation/RCTNativeAnimatedModule.m index 8426d8bb8..75357f6d6 100644 --- a/Libraries/NativeAnimation/RCTNativeAnimatedModule.m +++ b/Libraries/NativeAnimation/RCTNativeAnimatedModule.m @@ -225,6 +225,18 @@ RCT_EXPORT_METHOD(flattenAnimatedNodeOffset:(nonnull NSNumber *)nodeTag) [valueNode flattenOffset]; } +RCT_EXPORT_METHOD(extractAnimatedNodeOffset:(nonnull NSNumber *)nodeTag) +{ + RCTAnimatedNode *node = _animationNodes[nodeTag]; + if (![node isKindOfClass:[RCTValueAnimatedNode class]]) { + RCTLogError(@"Not a value node."); + return; + } + + RCTValueAnimatedNode *valueNode = (RCTValueAnimatedNode *)node; + [valueNode extractOffset]; +} + RCT_EXPORT_METHOD(connectAnimatedNodeToView:(nonnull NSNumber *)nodeTag viewTag:(nonnull NSNumber *)viewTag) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java index 5ae7294ee..4424d2e28 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java @@ -262,6 +262,16 @@ public class NativeAnimatedModule extends ReactContextBaseJavaModule implements }); } + @ReactMethod + public void extractAnimatedNodeOffset(final int tag) { + mOperations.add(new UIThreadOperation() { + @Override + public void execute(NativeAnimatedNodesManager animatedNodesManager) { + animatedNodesManager.extractAnimatedNodeOffset(tag); + } + }); + } + @ReactMethod public void startAnimatingNode( final int animationId, diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java index 622c497a6..b77a53c7f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java @@ -157,6 +157,15 @@ import javax.annotation.Nullable; ((ValueAnimatedNode) node).flattenOffset(); } + public void extractAnimatedNodeOffset(int tag) { + AnimatedNode node = mAnimatedNodes.get(tag); + if (node == null || !(node instanceof ValueAnimatedNode)) { + throw new JSApplicationIllegalArgumentException("Animated node with tag " + tag + + " does not exists or is not a 'value' node"); + } + ((ValueAnimatedNode) node).extractOffset(); + } + public void startAnimatingNode( int animationId, int animatedNodeTag, diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java index dfaa8330a..fb545da9b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java @@ -40,6 +40,11 @@ import javax.annotation.Nullable; mOffset = 0; } + public void extractOffset() { + mOffset += mValue; + mValue = 0; + } + public void onValueUpdate() { if (mValueListener == null) { return;