Support for Animated.interpolate

Summary:This change adds native animated support for Animated.interpolate

Animated.interpolate allows for defining nodes that outputs an interpolated value of their input node based on the interpolation node configuration. For now native animated implementation only supports a linear interpolation for a given input and output ranges (ranges can consists of multiple segments). Native interpolation node is compatible with the JS implementation with the exception that not all attributes that can be used in JS are supported. Before we migrate interpolation node from JS->native we verify that only supported props are used.

**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/7141

Differential Revision: D3216546

fb-gh-sync-id: 29876e33956615c6370ca4d332abe048f8dba5b8
fbshipit-source-id: 29876e33956615c6370ca4d332abe048f8dba5b8
This commit is contained in:
Krzysztof Magiera
2016-04-23 02:37:01 -07:00
committed by Facebook Github Bot 9
parent a31e87b3f2
commit dd244f5530
7 changed files with 296 additions and 8 deletions

View File

@@ -0,0 +1,64 @@
package com.facebook.react.animated;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import static org.fest.assertions.api.Assertions.assertThat;
/**
* Tests method used by {@link InterpolationAnimatedNode} to interpolate value of the input nodes.
*/
@RunWith(RobolectricTestRunner.class)
public class NativeAnimatedInterpolationTest {
@Test
public void testSimpleOneToOneMapping() {
double[] input = new double[] {0d, 1d};
double[] output = new double[] {0d, 1d};
assertThat(InterpolationAnimatedNode.interpolate(0, input, output)).isEqualTo(0);
assertThat(InterpolationAnimatedNode.interpolate(0.5, input, output)).isEqualTo(0.5);
assertThat(InterpolationAnimatedNode.interpolate(0.8, input, output)).isEqualTo(0.8);
assertThat(InterpolationAnimatedNode.interpolate(1, input, output)).isEqualTo(1);
}
@Test
public void testWiderOutputRange() {
double[] input = new double[] {0d, 1d};
double[] output = new double[] {100d, 200d};
assertThat(InterpolationAnimatedNode.interpolate(0, input, output)).isEqualTo(100);
assertThat(InterpolationAnimatedNode.interpolate(0.5, input, output)).isEqualTo(150);
assertThat(InterpolationAnimatedNode.interpolate(0.8, input, output)).isEqualTo(180);
assertThat(InterpolationAnimatedNode.interpolate(1, input, output)).isEqualTo(200);
}
@Test
public void testWiderInputRange() {
double[] input = new double[] {2000d, 3000d};
double[] output = new double[] {1d, 2d};
assertThat(InterpolationAnimatedNode.interpolate(2000, input, output)).isEqualTo(1);
assertThat(InterpolationAnimatedNode.interpolate(2250, input, output)).isEqualTo(1.25);
assertThat(InterpolationAnimatedNode.interpolate(2800, input, output)).isEqualTo(1.8);
assertThat(InterpolationAnimatedNode.interpolate(3000, input, output)).isEqualTo(2);
}
@Test
public void testManySegments() {
double[] input = new double[] {-1d, 1d, 5d};
double[] output = new double[] {0, 10d, 20d};
assertThat(InterpolationAnimatedNode.interpolate(-1, input, output)).isEqualTo(0);
assertThat(InterpolationAnimatedNode.interpolate(0, input, output)).isEqualTo(5);
assertThat(InterpolationAnimatedNode.interpolate(1, input, output)).isEqualTo(10);
assertThat(InterpolationAnimatedNode.interpolate(2, input, output)).isEqualTo(12.5);
assertThat(InterpolationAnimatedNode.interpolate(5, input, output)).isEqualTo(20);
}
@Test
public void testExtrapolate() {
double[] input = new double[] {10d, 20d};
double[] output = new double[] {0d, 1d};
assertThat(InterpolationAnimatedNode.interpolate(30d, input, output)).isEqualTo(2);
assertThat(InterpolationAnimatedNode.interpolate(5d, input, output)).isEqualTo(-0.5);
}
}

View File

@@ -462,4 +462,61 @@ public class NativeAnimatedNodeTraversalTest {
verifyNoMoreInteractions(mUIImplementationMock);
verifyNoMoreInteractions(animationCallback);
}
@Test
public void testInterpolationNode() {
mNativeAnimatedNodesManager.createAnimatedNode(
1,
JavaOnlyMap.of("type", "value", "value", 10d));
mNativeAnimatedNodesManager.createAnimatedNode(
2,
JavaOnlyMap.of(
"type",
"interpolation",
"inputRange",
JavaOnlyArray.of(10d, 20d),
"outputRange",
JavaOnlyArray.of(0d, 1d)));
mNativeAnimatedNodesManager.createAnimatedNode(
3,
JavaOnlyMap.of("type", "style", "style", JavaOnlyMap.of("opacity", 2)));
mNativeAnimatedNodesManager.createAnimatedNode(
4,
JavaOnlyMap.of("type", "props", "props", JavaOnlyMap.of("style", 3)));
mNativeAnimatedNodesManager.connectAnimatedNodes(1, 2);
mNativeAnimatedNodesManager.connectAnimatedNodes(2, 3);
mNativeAnimatedNodesManager.connectAnimatedNodes(3, 4);
mNativeAnimatedNodesManager.connectAnimatedNodeToView(4, 50);
Callback animationCallback = mock(Callback.class);
JavaOnlyArray frames = JavaOnlyArray.of(0d, 0.2d, 0.4d, 0.6d, 0.8d, 1d);
mNativeAnimatedNodesManager.startAnimatingNode(
1,
1,
JavaOnlyMap.of("type", "frames", "frames", frames, "toValue", 20d),
animationCallback);
ArgumentCaptor<ReactStylesDiffMap> stylesCaptor =
ArgumentCaptor.forClass(ReactStylesDiffMap.class);
reset(mUIImplementationMock);
mNativeAnimatedNodesManager.runUpdates(nextFrameTime());
verify(mUIImplementationMock).synchronouslyUpdateViewOnUIThread(eq(50), stylesCaptor.capture());
assertThat(stylesCaptor.getValue().getDouble("opacity", Double.NaN)).isEqualTo(0d);
for (int i = 0; i < frames.size(); i++) {
reset(mUIImplementationMock);
mNativeAnimatedNodesManager.runUpdates(nextFrameTime());
verify(mUIImplementationMock)
.synchronouslyUpdateViewOnUIThread(eq(50), stylesCaptor.capture());
assertThat(stylesCaptor.getValue().getDouble("opacity", Double.NaN))
.isEqualTo(frames.getDouble(i));
}
reset(mUIImplementationMock);
mNativeAnimatedNodesManager.runUpdates(nextFrameTime());
verifyNoMoreInteractions(mUIImplementationMock);
}
}