Implement NativeAnimated offsets on Android

Summary:
This diff implements NativeAnimation offsets on Android. Running the examples should show no change; however, calling `setOffset()` should offset the final value for any value node by that amount. This brings Android up to date with JS and iOS animation APIs.
Closes https://github.com/facebook/react-native/pull/10680

Differential Revision: D4119609

fbshipit-source-id: 96dccdf25f67c64c6787fd9ac762ec841cefc46a
This commit is contained in:
Ryan Gomba 2016-11-02 13:46:47 -07:00 committed by Facebook Github Bot
parent 68c61203ac
commit 8e81644f64
12 changed files with 64 additions and 14 deletions

View File

@ -39,7 +39,7 @@ import com.facebook.react.bridge.ReadableMap;
for (int i = 0; i < mInputNodes.length; i++) {
AnimatedNode animatedNode = mNativeAnimatedNodesManager.getNodeById(mInputNodes[i]);
if (animatedNode != null && animatedNode instanceof ValueAnimatedNode) {
mValue += ((ValueAnimatedNode) animatedNode).mValue;
mValue += ((ValueAnimatedNode) animatedNode).getValue();
} else {
throw new JSApplicationCausedNativeException("Illegal node ID set as an input for " +
"Animated.Add node");

View File

@ -48,6 +48,6 @@ import com.facebook.react.bridge.ReadableMap;
}
return ((ValueAnimatedNode) animatedNode).mValue;
return ((ValueAnimatedNode) animatedNode).getValue();
}
}

View File

@ -38,7 +38,7 @@ import com.facebook.react.bridge.ReadableMap;
for (int i = 0; i < mInputNodes.length; i++) {
AnimatedNode animatedNode = mNativeAnimatedNodesManager.getNodeById(mInputNodes[i]);
if (animatedNode != null && animatedNode instanceof ValueAnimatedNode) {
double value = ((ValueAnimatedNode) animatedNode).mValue;
double value = ((ValueAnimatedNode) animatedNode).getValue();
if (i == 0) {
mValue = value;
continue;

View File

@ -136,6 +136,6 @@ import javax.annotation.Nullable;
throw new IllegalStateException("Trying to update interpolation node that has not been " +
"attached to the parent");
}
mValue = interpolate(mParent.mValue, mInputRange, mOutputRange, mExtrapolateLeft, mExtrapolateRight);
mValue = interpolate(mParent.getValue(), mInputRange, mOutputRange, mExtrapolateLeft, mExtrapolateRight);
}
}

View File

@ -39,7 +39,7 @@ import com.facebook.react.bridge.ReadableMap;
for (int i = 0; i < mInputNodes.length; i++) {
AnimatedNode animatedNode = mNativeAnimatedNodesManager.getNodeById(mInputNodes[i]);
if (animatedNode != null && animatedNode instanceof ValueAnimatedNode) {
mValue *= ((ValueAnimatedNode) animatedNode).mValue;
mValue *= ((ValueAnimatedNode) animatedNode).getValue();
} else {
throw new JSApplicationCausedNativeException("Illegal node ID set as an input for " +
"Animated.multiply node");

View File

@ -242,6 +242,26 @@ public class NativeAnimatedModule extends ReactContextBaseJavaModule implements
});
}
@ReactMethod
public void setAnimatedNodeOffset(final int tag, final double value) {
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NativeAnimatedNodesManager animatedNodesManager) {
animatedNodesManager.setAnimatedNodeOffset(tag, value);
}
});
}
@ReactMethod
public void flattenAnimatedNodeOffset(final int tag) {
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NativeAnimatedNodesManager animatedNodesManager) {
animatedNodesManager.flattenAnimatedNodeOffset(tag);
}
});
}
@ReactMethod
public void startAnimatingNode(
final int animationId,

View File

@ -136,6 +136,25 @@ import javax.annotation.Nullable;
mUpdatedNodes.add(node);
}
public void setAnimatedNodeOffset(int tag, double offset) {
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).mOffset = offset;
mUpdatedNodes.add(node);
}
public void flattenAnimatedNodeOffset(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).flattenOffset();
}
public void startAnimatingNode(
int animationId,
int animatedNodeTag,

View File

@ -56,7 +56,7 @@ import javax.annotation.Nullable;
} else if (node instanceof StyleAnimatedNode) {
((StyleAnimatedNode) node).collectViewUpdates(propsMap);
} else if (node instanceof ValueAnimatedNode) {
propsMap.putDouble(entry.getKey(), ((ValueAnimatedNode) node).mValue);
propsMap.putDouble(entry.getKey(), ((ValueAnimatedNode) node).getValue());
} else {
throw new IllegalArgumentException("Unsupported type of node used in property node " +
node.getClass());

View File

@ -46,7 +46,7 @@ import javax.annotation.Nullable;
} else if (node instanceof TransformAnimatedNode) {
((TransformAnimatedNode) node).collectViewUpdates(propsMap);
} else if (node instanceof ValueAnimatedNode) {
propsMap.putDouble(entry.getKey(), ((ValueAnimatedNode) node).mValue);
propsMap.putDouble(entry.getKey(), ((ValueAnimatedNode) node).getValue());
} else {
throw new IllegalArgumentException("Unsupported type of node used in property node " +
node.getClass());

View File

@ -70,7 +70,7 @@ import java.util.List;
if (node == null) {
throw new IllegalArgumentException("Mapped style node does not exists");
} else if (node instanceof ValueAnimatedNode) {
value = ((ValueAnimatedNode) node).mValue;
value = ((ValueAnimatedNode) node).getValue();
} else {
throw new IllegalArgumentException("Unsupported type of node used as a transform child " +
"node " + node.getClass());

View File

@ -19,6 +19,7 @@ import javax.annotation.Nullable;
*/
/*package*/ class ValueAnimatedNode extends AnimatedNode {
/*package*/ double mValue = Double.NaN;
/*package*/ double mOffset = 0;
private @Nullable AnimatedNodeValueListener mValueListener;
public ValueAnimatedNode() {
@ -27,6 +28,16 @@ import javax.annotation.Nullable;
public ValueAnimatedNode(ReadableMap config) {
mValue = config.getDouble("value");
mOffset = config.getDouble("offset");
}
public double getValue() {
return mOffset + mValue;
}
public void flattenOffset() {
mValue += mOffset;
mOffset = 0;
}
public void onValueUpdate() {

View File

@ -121,7 +121,7 @@ public class NativeAnimatedNodeTraversalTest {
private void createSimpleAnimatedViewWithOpacity(int viewTag, double opacity) {
mNativeAnimatedNodesManager.createAnimatedNode(
1,
JavaOnlyMap.of("type", "value", "value", opacity));
JavaOnlyMap.of("type", "value", "value", opacity, "offset", 0d));
mNativeAnimatedNodesManager.createAnimatedNode(
2,
JavaOnlyMap.of("type", "style", "style", JavaOnlyMap.of("opacity", 1)));
@ -387,10 +387,10 @@ public class NativeAnimatedNodeTraversalTest {
double secondValue) {
mNativeAnimatedNodesManager.createAnimatedNode(
1,
JavaOnlyMap.of("type", "value", "value", 100d));
JavaOnlyMap.of("type", "value", "value", 100d, "offset", 0d));
mNativeAnimatedNodesManager.createAnimatedNode(
2,
JavaOnlyMap.of("type", "value", "value", 1000d));
JavaOnlyMap.of("type", "value", "value", 1000d, "offset", 0d));
mNativeAnimatedNodesManager.createAnimatedNode(
3,
@ -558,10 +558,10 @@ public class NativeAnimatedNodeTraversalTest {
public void testMultiplicationNode() {
mNativeAnimatedNodesManager.createAnimatedNode(
1,
JavaOnlyMap.of("type", "value", "value", 1d));
JavaOnlyMap.of("type", "value", "value", 1d, "offset", 0d));
mNativeAnimatedNodesManager.createAnimatedNode(
2,
JavaOnlyMap.of("type", "value", "value", 5d));
JavaOnlyMap.of("type", "value", "value", 5d, "offset", 0d));
mNativeAnimatedNodesManager.createAnimatedNode(
3,
@ -669,7 +669,7 @@ public class NativeAnimatedNodeTraversalTest {
public void testInterpolationNode() {
mNativeAnimatedNodesManager.createAnimatedNode(
1,
JavaOnlyMap.of("type", "value", "value", 10d));
JavaOnlyMap.of("type", "value", "value", 10d, "offset", 0d));
mNativeAnimatedNodesManager.createAnimatedNode(
2,