diff --git a/Examples/UIExplorer/js/NativeAnimationsExample.js b/Examples/UIExplorer/js/NativeAnimationsExample.js index bd7add201..b4c151c53 100644 --- a/Examples/UIExplorer/js/NativeAnimationsExample.js +++ b/Examples/UIExplorer/js/NativeAnimationsExample.js @@ -335,7 +335,7 @@ exports.examples = [ inputRange: [0, 1], outputRange: [0, 100], }) - } + }, ], } ]} diff --git a/Examples/UIExplorer/js/UIExplorerList.android.js b/Examples/UIExplorer/js/UIExplorerList.android.js index 58b4f7b04..f35a34db4 100644 --- a/Examples/UIExplorer/js/UIExplorerList.android.js +++ b/Examples/UIExplorer/js/UIExplorerList.android.js @@ -50,10 +50,6 @@ var ComponentExamples: Array = [ key: 'ModalExample', module: require('./ModalExample'), }, - { - key: 'NativeAnimationsExample', - module: require('./NativeAnimationsExample'), - }, { key: 'PickerExample', module: require('./PickerExample'), @@ -121,6 +117,10 @@ const APIExamples = [ key: 'AlertExample', module: require('./AlertExample').AlertExample, }, + { + key: 'AnimatedExample', + module: require('./AnimatedExample'), + }, { key: 'AppStateExample', module: require('./AppStateExample'), @@ -165,6 +165,10 @@ const APIExamples = [ key: 'LayoutExample', module: require('./LayoutExample'), }, + { + key: 'NativeAnimationsExample', + module: require('./NativeAnimationsExample'), + }, { key: 'NavigationExperimentalExample', module: require('./NavigationExperimental/NavigationExperimentalExample'), diff --git a/Examples/UIExplorer/js/UIExplorerList.ios.js b/Examples/UIExplorer/js/UIExplorerList.ios.js index 044c770da..2e996c065 100644 --- a/Examples/UIExplorer/js/UIExplorerList.ios.js +++ b/Examples/UIExplorer/js/UIExplorerList.ios.js @@ -68,10 +68,6 @@ const ComponentExamples: Array = [ key: 'ModalExample', module: require('./ModalExample'), }, - { - key: 'NativeAnimationsExample', - module: require('./NativeAnimationsExample'), - }, { key: 'NavigatorExample', module: require('./Navigator/NavigatorExample'), @@ -227,6 +223,10 @@ const APIExamples: Array = [ key: 'LinkingExample', module: require('./LinkingExample'), }, + { + key: 'NativeAnimationsExample', + module: require('./NativeAnimationsExample'), + }, { key: 'NavigationExperimentalExample', module: require('./NavigationExperimental/NavigationExperimentalExample'), diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js index 02c984f83..f21ed5be2 100644 --- a/Libraries/Animated/src/AnimatedImplementation.js +++ b/Libraries/Animated/src/AnimatedImplementation.js @@ -1251,9 +1251,16 @@ class AnimatedTransform extends AnimatedWithChildren { var value = transform[key]; if (value instanceof Animated) { transConfigs.push({ + type: 'animated', property: key, nodeTag: value.__getNativeTag(), }); + } else { + transConfigs.push({ + type: 'static', + property: key, + value, + }); } } }); diff --git a/Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.m index 2f2799ff8..d44fe4d7c 100644 --- a/Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.m +++ b/Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.m @@ -37,6 +37,12 @@ NSArray *transformConfigs = self.config[@"transforms"]; for (NSDictionary *transformConfig in transformConfigs) { + NSString *type = transformConfig[@"type"]; + // TODO: Support static transform values. + if (![type isEqualToString: @"animated"]) { + continue; + } + NSNumber *nodeTag = transformConfig[@"nodeTag"]; RCTAnimatedNode *node = self.parentNodes[nodeTag]; diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedAddition.java b/ReactAndroid/src/main/java/com/facebook/react/animated/AdditionAnimatedNode.java similarity index 82% rename from ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedAddition.java rename to ReactAndroid/src/main/java/com/facebook/react/animated/AdditionAnimatedNode.java index 3c538e08d..34b96be57 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedAddition.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/AdditionAnimatedNode.java @@ -1,3 +1,12 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + package com.facebook.react.animated; import com.facebook.react.bridge.JSApplicationCausedNativeException; diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/MultiplicationAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/MultiplicationAnimatedNode.java index 9fe8d7a81..5838ed0c5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/MultiplicationAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/MultiplicationAnimatedNode.java @@ -1,3 +1,12 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + package com.facebook.react.animated; import com.facebook.react.bridge.JSApplicationCausedNativeException; 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 deb236155..67a735e16 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java @@ -78,6 +78,8 @@ import javax.annotation.Nullable; node = new AdditionAnimatedNode(config, this); } else if ("multiplication".equals(type)) { node = new MultiplicationAnimatedNode(config, this); + } else if ("transform".equals(type)) { + node = new TransformAnimatedNode(config, this); } else { throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/StyleAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/StyleAnimatedNode.java index de7c1b054..f23cf248a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/StyleAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/StyleAnimatedNode.java @@ -43,6 +43,8 @@ import javax.annotation.Nullable; @Nullable AnimatedNode node = mNativeAnimatedNodesManager.getNodeById(entry.getValue()); if (node == null) { throw new IllegalArgumentException("Mapped style node does not exists"); + } else if (node instanceof TransformAnimatedNode) { + ((TransformAnimatedNode) node).collectViewUpdates(propsMap); } else if (node instanceof ValueAnimatedNode) { propsMap.putDouble(entry.getKey(), ((ValueAnimatedNode) node).mValue); } else { diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/TransformAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/TransformAnimatedNode.java new file mode 100644 index 000000000..69213dcde --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/TransformAnimatedNode.java @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package com.facebook.react.animated; + +import com.facebook.react.bridge.JavaOnlyArray; +import com.facebook.react.bridge.JavaOnlyMap; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; + +import java.util.ArrayList; +import java.util.List; + +/** + * Native counterpart of transform animated node (see AnimatedTransform class in AnimatedImplementation.js) + */ +/* package */ class TransformAnimatedNode extends AnimatedNode { + + private class TransformConfig { + public String mProperty; + } + + private class AnimatedTransformConfig extends TransformConfig { + public int mNodeTag; + } + + private class StaticTransformConfig extends TransformConfig { + public double mValue; + } + + private final NativeAnimatedNodesManager mNativeAnimatedNodesManager; + private final List mTransformConfigs; + + TransformAnimatedNode(ReadableMap config, NativeAnimatedNodesManager nativeAnimatedNodesManager) { + ReadableArray transforms = config.getArray("transforms"); + mTransformConfigs = new ArrayList<>(transforms.size()); + for (int i = 0; i < transforms.size(); i++) { + ReadableMap transformConfigMap = transforms.getMap(i); + String property = transformConfigMap.getString("property"); + String type = transformConfigMap.getString("type"); + if (type.equals("animated")) { + AnimatedTransformConfig transformConfig = new AnimatedTransformConfig(); + transformConfig.mProperty = property; + transformConfig.mNodeTag = transformConfigMap.getInt("nodeTag"); + mTransformConfigs.add(transformConfig); + } else { + StaticTransformConfig transformConfig = new StaticTransformConfig(); + transformConfig.mProperty = property; + transformConfig.mValue = transformConfigMap.getDouble("value"); + mTransformConfigs.add(transformConfig); + } + } + mNativeAnimatedNodesManager = nativeAnimatedNodesManager; + } + + public void collectViewUpdates(JavaOnlyMap propsMap) { + List transforms = new ArrayList<>(mTransformConfigs.size()); + + for (TransformConfig transformConfig : mTransformConfigs) { + double value; + if (transformConfig instanceof AnimatedTransformConfig) { + int nodeTag = ((AnimatedTransformConfig) transformConfig).mNodeTag; + AnimatedNode node = mNativeAnimatedNodesManager.getNodeById(nodeTag); + if (node == null) { + throw new IllegalArgumentException("Mapped style node does not exists"); + } else if (node instanceof ValueAnimatedNode) { + value = ((ValueAnimatedNode) node).mValue; + } else { + throw new IllegalArgumentException("Unsupported type of node used as a transform child " + + "node " + node.getClass()); + } + } else { + value = ((StaticTransformConfig) transformConfig).mValue; + } + + transforms.add(JavaOnlyMap.of(transformConfig.mProperty, value)); + } + + propsMap.putArray("transform", JavaOnlyArray.from(transforms)); + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java index 607d686e2..c9e7c3114 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java @@ -90,7 +90,23 @@ public class JavaOnlyMap implements ReadableMap, WritableMap { @Override public ReadableType getType(String name) { - throw new UnsupportedOperationException("Method not implemented"); + Object value = mBackingMap.get(name); + if (value == null) { + return ReadableType.Null; + } else if (value instanceof Number) { + return ReadableType.Number; + } else if (value instanceof String) { + return ReadableType.String; + } else if (value instanceof Boolean) { + return ReadableType.Boolean; + } else if (value instanceof ReadableMap) { + return ReadableType.Map; + } else if (value instanceof ReadableArray) { + return ReadableType.Array; + } else { + throw new IllegalArgumentException("Invalid value " + value.toString() + " for key " + name + + "contained in JavaOnlyMap"); + } } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java index c233d9407..52895d4b7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.java @@ -20,13 +20,13 @@ public class TransformHelper { private static double convertToRadians(ReadableMap transformMap, String key) { double value; - boolean inRadians = false; + boolean inRadians = true; if (transformMap.getType(key) == ReadableType.String) { String stringValue = transformMap.getString(key); if (stringValue.endsWith("rad")) { - inRadians = true; stringValue = stringValue.substring(0, stringValue.length() - 3); } else if (stringValue.endsWith("deg")) { + inRadians = false; stringValue = stringValue.substring(0, stringValue.length() - 3); } value = Float.parseFloat(stringValue);