Skip to content

Commit

Permalink
Stop native driver animations when value is set.
Browse files Browse the repository at this point in the history
Summary:
This diff changes the behaviour of natively driven animations in case the node that they are being run for has its value changed using `setValue` or as a result of an incoming event.

The reason for changing that is to match the JS implementation of `setValue` which behaves as described above (see relevant code here: https://github.com/facebook/react-native/blob/7cdd4d48c89ad642a1c107e0b40c25eb75682175/Libraries/Animated/src/AnimatedImplementation.js#L743)

**Test Plan:**
Use this sample app: https://snack.expo.io/B1V7RX9r-
Change: `USE_NATIVE_DRIVER` const between `true` and `false`.
See the animation stops regardless of the state of `USE_NATIVE_DRIVER` unlike before when it would stop only when `USE_NATIVE_DRIVER` was set to `false`
Closes #15054

Differential Revision: D5463750

Pulled By: hramos

fbshipit-source-id: e164c5299588ba8cac2937260c9ba9f6053b04e5
  • Loading branch information
kmagiera authored and facebook-github-bot committed Jul 20, 2017
1 parent 2334899 commit b8fafb4
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
16 changes: 16 additions & 0 deletions Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ - (void)setAnimatedNodeValue:(nonnull NSNumber *)nodeTag
RCTLogError(@"Not a value node.");
return;
}
[self stopAnimationsForNode:node];

RCTValueAnimatedNode *valueNode = (RCTValueAnimatedNode *)node;
valueNode.value = value.floatValue;
Expand Down Expand Up @@ -264,6 +265,20 @@ - (void)stopAnimation:(nonnull NSNumber *)animationId
}
}

- (void)stopAnimationsForNode:(nonnull RCTAnimatedNode *)node
{
NSMutableArray<id<RCTAnimationDriver>> *discarded = [NSMutableArray new];
for (id<RCTAnimationDriver> driver in _activeAnimations) {
if ([driver.valueNode isEqual:node]) {
[discarded addObject:driver];
}
}
for (id<RCTAnimationDriver> driver in discarded) {
[driver stopAnimation];
[_activeAnimations removeObject:driver];
}
}

#pragma mark -- Events

- (void)addAnimatedEventToView:(nonnull NSNumber *)viewTag
Expand Down Expand Up @@ -328,6 +343,7 @@ - (void)handleAnimatedEvent:(id<RCTEvent>)event
NSMutableArray<RCTEventAnimation *> *driversForKey = _eventDrivers[key];
if (driversForKey) {
for (RCTEventAnimation *driver in driversForKey) {
[self stopAnimationsForNode:driver.valueNode];
[driver updateWithEvent:event];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
Expand Down Expand Up @@ -145,6 +144,7 @@ public void setAnimatedNodeValue(int tag, double value) {
throw new JSApplicationIllegalArgumentException("Animated node with tag " + tag +
" does not exists or is not a 'value' node");
}
stopAnimationsForNode(node);
((ValueAnimatedNode) node).mValue = value;
mUpdatedNodes.put(tag, node);
}
Expand Down Expand Up @@ -208,6 +208,24 @@ public void startAnimatingNode(
mActiveAnimations.put(animationId, animation);
}

private void stopAnimationsForNode(AnimatedNode animatedNode) {
// in most of the cases there should never be more than a few active animations running at the
// same time. Therefore it does not make much sense to create an animationId -> animation
// object map that would require additional memory just to support the use-case of stopping
// an animation
for (int i = 0; i < mActiveAnimations.size(); i++) {
AnimationDriver animation = mActiveAnimations.valueAt(i);
if (animatedNode.equals(animation.mAnimatedValue)) {
// Invoke animation end callback with {finished: false}
WritableMap endCallbackResponse = Arguments.createMap();
endCallbackResponse.putBoolean("finished", false);
animation.mEndCallback.invoke(endCallbackResponse);
mActiveAnimations.removeAt(i);
i--;
}
}
}

public void stopAnimation(int animationId) {
// in most of the cases there should never be more than a few active animations running at the
// same time. Therefore it does not make much sense to create an animationId -> animation
Expand Down Expand Up @@ -362,6 +380,7 @@ public void onEventDispatch(Event event) {
List<EventAnimationDriver> driversForKey = mEventDrivers.get(event.getViewTag() + eventName);
if (driversForKey != null) {
for (EventAnimationDriver driver : driversForKey) {
stopAnimationsForNode(driver.mValueNode);
event.dispatch(driver);
mRunUpdateNodeList.add(driver.mValueNode);
}
Expand Down

0 comments on commit b8fafb4

Please sign in to comment.