mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-05 17:30:38 +08:00
Support for stopping animations that run on UI thread.
Summary:This change extends animated native module API with `stopAnimation` method that is responsible for interrupting actively running animation as a reslut of a JS call. In order for the `stopAnimation` to understand `animationId` argument I also had to add `animationId` to `startAnimation` method. As JS thread runs in parallel to the thread which executes the animation there is a chance that JS may call `stopAnimation` after the animation has finished. Because of that we are not doing any checks on the `animationId` parameter passed to `stopAnimation` in native and if the animation does not exists in the registry we ignore that call. **Test Plan** Run JS tests: `npm test Libraries/Animated/src/__tests__/AnimatedNative-test.js` Run java tests: `buck test ReactAndroid/src/test/java/com/facebook/react/animated` Closes https://github.com/facebook/react-native/pull/7058 Differential Revision: D3211906 fb-gh-sync-id: 3761509651de36a550b00d33e2a631c379d3900f fbshipit-source-id: 3761509651de36a550b00d33e2a631c379d3900f
This commit is contained in:
committed by
Facebook Github Bot 8
parent
63adb48dc4
commit
cd11738819
@@ -32,9 +32,12 @@ import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
@@ -110,6 +113,7 @@ public class NativeAnimatedNodeTraversalTest {
|
||||
JavaOnlyArray frames = JavaOnlyArray.of(0d, 0.2d, 0.4d, 0.6d, 0.8d, 1d);
|
||||
Callback animationCallback = mock(Callback.class);
|
||||
mNativeAnimatedNodesManager.startAnimatingNode(
|
||||
1,
|
||||
1,
|
||||
JavaOnlyMap.of("type", "frames", "frames", frames, "toValue", 1d),
|
||||
animationCallback);
|
||||
@@ -143,6 +147,7 @@ public class NativeAnimatedNodeTraversalTest {
|
||||
JavaOnlyArray frames = JavaOnlyArray.of(0d, 1d);
|
||||
Callback animationCallback = mock(Callback.class);
|
||||
mNativeAnimatedNodesManager.startAnimatingNode(
|
||||
1,
|
||||
1,
|
||||
JavaOnlyMap.of("type", "frames", "frames", frames, "toValue", 1d),
|
||||
animationCallback);
|
||||
@@ -209,11 +214,13 @@ public class NativeAnimatedNodeTraversalTest {
|
||||
Callback animationCallback = mock(Callback.class);
|
||||
JavaOnlyArray frames = JavaOnlyArray.of(0d, 1d);
|
||||
mNativeAnimatedNodesManager.startAnimatingNode(
|
||||
1,
|
||||
1,
|
||||
JavaOnlyMap.of("type", "frames", "frames", frames, "toValue", 101d),
|
||||
animationCallback);
|
||||
|
||||
mNativeAnimatedNodesManager.startAnimatingNode(
|
||||
2,
|
||||
2,
|
||||
JavaOnlyMap.of("type", "frames", "frames", frames, "toValue", 1010d),
|
||||
animationCallback);
|
||||
@@ -258,6 +265,7 @@ public class NativeAnimatedNodeTraversalTest {
|
||||
Callback animationCallback = mock(Callback.class);
|
||||
JavaOnlyArray frames = JavaOnlyArray.of(0d, 1d);
|
||||
mNativeAnimatedNodesManager.startAnimatingNode(
|
||||
1,
|
||||
1,
|
||||
JavaOnlyMap.of("type", "frames", "frames", frames, "toValue", 101d),
|
||||
animationCallback);
|
||||
@@ -304,6 +312,7 @@ public class NativeAnimatedNodeTraversalTest {
|
||||
// Start animating for the first addition input node, will have 2 frames only
|
||||
JavaOnlyArray firstFrames = JavaOnlyArray.of(0d, 1d);
|
||||
mNativeAnimatedNodesManager.startAnimatingNode(
|
||||
1,
|
||||
1,
|
||||
JavaOnlyMap.of("type", "frames", "frames", firstFrames, "toValue", 200d),
|
||||
animationCallback);
|
||||
@@ -311,6 +320,7 @@ public class NativeAnimatedNodeTraversalTest {
|
||||
// Start animating for the first addition input node, will have 6 frames
|
||||
JavaOnlyArray secondFrames = JavaOnlyArray.of(0d, 0.2d, 0.4d, 0.6d, 0.8d, 1d);
|
||||
mNativeAnimatedNodesManager.startAnimatingNode(
|
||||
2,
|
||||
2,
|
||||
JavaOnlyMap.of("type", "frames", "frames", secondFrames, "toValue", 1010d),
|
||||
animationCallback);
|
||||
@@ -370,11 +380,13 @@ public class NativeAnimatedNodeTraversalTest {
|
||||
Callback animationCallback = mock(Callback.class);
|
||||
JavaOnlyArray frames = JavaOnlyArray.of(0d, 1d);
|
||||
mNativeAnimatedNodesManager.startAnimatingNode(
|
||||
1,
|
||||
1,
|
||||
JavaOnlyMap.of("type", "frames", "frames", frames, "toValue", 2d),
|
||||
animationCallback);
|
||||
|
||||
mNativeAnimatedNodesManager.startAnimatingNode(
|
||||
2,
|
||||
2,
|
||||
JavaOnlyMap.of("type", "frames", "frames", frames, "toValue", 10d),
|
||||
animationCallback);
|
||||
@@ -401,4 +413,53 @@ public class NativeAnimatedNodeTraversalTest {
|
||||
mNativeAnimatedNodesManager.runUpdates(nextFrameTime());
|
||||
verifyNoMoreInteractions(mUIImplementationMock);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test verifies that when {@link NativeAnimatedModule#stopAnimation} is called the animation
|
||||
* will no longer be updating the nodes it has been previously attached to and that the animation
|
||||
* callback will be triggered with {@code {finished: false}}
|
||||
*/
|
||||
@Test
|
||||
public void testHandleStoppingAnimation() {
|
||||
createSimpleAnimatedViewWithOpacity(1000, 0d);
|
||||
|
||||
JavaOnlyArray frames = JavaOnlyArray.of(0d, 0.2d, 0.4d, 0.6d, 0.8d, 1.0d);
|
||||
Callback animationCallback = mock(Callback.class);
|
||||
mNativeAnimatedNodesManager.startAnimatingNode(
|
||||
404,
|
||||
1,
|
||||
JavaOnlyMap.of("type", "frames", "frames", frames, "toValue", 1d),
|
||||
animationCallback);
|
||||
|
||||
ArgumentCaptor<ReadableMap> callbackResponseCaptor = ArgumentCaptor.forClass(ReadableMap.class);
|
||||
|
||||
reset(animationCallback);
|
||||
reset(mUIImplementationMock);
|
||||
mNativeAnimatedNodesManager.runUpdates(nextFrameTime());
|
||||
mNativeAnimatedNodesManager.runUpdates(nextFrameTime());
|
||||
verify(mUIImplementationMock, times(2))
|
||||
.synchronouslyUpdateViewOnUIThread(anyInt(), any(ReactStylesDiffMap.class));
|
||||
verifyNoMoreInteractions(animationCallback);
|
||||
|
||||
reset(animationCallback);
|
||||
reset(mUIImplementationMock);
|
||||
mNativeAnimatedNodesManager.stopAnimation(404);
|
||||
verify(animationCallback).invoke(callbackResponseCaptor.capture());
|
||||
verifyNoMoreInteractions(animationCallback);
|
||||
verifyNoMoreInteractions(mUIImplementationMock);
|
||||
|
||||
assertThat(callbackResponseCaptor.getValue().hasKey("finished")).isTrue();
|
||||
assertThat(callbackResponseCaptor.getValue().getBoolean("finished")).isFalse();
|
||||
|
||||
reset(animationCallback);
|
||||
reset(mUIImplementationMock);
|
||||
// Run "update" loop a few more times -> we expect no further updates nor callback calls to be
|
||||
// triggered
|
||||
for (int i = 0; i < 5; i++) {
|
||||
mNativeAnimatedNodesManager.runUpdates(nextFrameTime());
|
||||
}
|
||||
|
||||
verifyNoMoreInteractions(mUIImplementationMock);
|
||||
verifyNoMoreInteractions(animationCallback);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user