From 95c7db90b807b9cf459f8a449d972ad11715f098 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Tue, 26 Mar 2019 17:07:34 -0700 Subject: [PATCH] Back out "[react-native][PR] Support Interpolation of strings when using native driver in Animated, fix Expected node to be marked as "native", optimize AnimatedNode creation and connections" Summary: Original commit changeset: 82a948a95419 Reviewed By: TheSavior Differential Revision: D14631845 fbshipit-source-id: f20d8150bccf50ea85388761e2f31ca4f97ae158 --- .../Animated/src/NativeAnimatedHelper.js | 3 +- .../Animated/src/animations/Animation.js | 1 - .../src/nodes/AnimatedInterpolation.js | 9 +- Libraries/Animated/src/nodes/AnimatedNode.js | 8 +- Libraries/Animated/src/nodes/AnimatedProps.js | 1 - Libraries/Animated/src/nodes/AnimatedStyle.js | 4 +- .../src/nodes/AnimatedWithChildren.js | 9 -- .../Nodes/RCTInterpolationAnimatedNode.m | 108 +----------------- .../Nodes/RCTPropsAnimatedNode.m | 9 +- .../Nodes/RCTValueAnimatedNode.h | 1 - .../animated/InterpolationAnimatedNode.java | 93 +-------------- .../react/animated/PropsAnimatedNode.java | 7 +- .../react/animated/ValueAnimatedNode.java | 5 - 13 files changed, 18 insertions(+), 240 deletions(-) diff --git a/Libraries/Animated/src/NativeAnimatedHelper.js b/Libraries/Animated/src/NativeAnimatedHelper.js index 307a0de9a..2ac39f024 100644 --- a/Libraries/Animated/src/NativeAnimatedHelper.js +++ b/Libraries/Animated/src/NativeAnimatedHelper.js @@ -271,7 +271,8 @@ function transformDataType(value: any): number { const radians = (degrees * Math.PI) / 180.0; return radians; } else { - return value; + // Assume radians + return parseFloat(value) || 0; } } diff --git a/Libraries/Animated/src/animations/Animation.js b/Libraries/Animated/src/animations/Animation.js index 5c35a1a90..b34ac9555 100644 --- a/Libraries/Animated/src/animations/Animation.js +++ b/Libraries/Animated/src/animations/Animation.js @@ -57,7 +57,6 @@ class Animation { } __startNativeAnimation(animatedValue: AnimatedValue): void { animatedValue.__makeNative(); - animatedValue.__connectAnimatedNodes(); this.__nativeId = NativeAnimatedHelper.generateNewAnimationId(); NativeAnimatedHelper.API.startAnimatingNode( this.__nativeId, diff --git a/Libraries/Animated/src/nodes/AnimatedInterpolation.js b/Libraries/Animated/src/nodes/AnimatedInterpolation.js index d42a4b893..1ba304d33 100644 --- a/Libraries/Animated/src/nodes/AnimatedInterpolation.js +++ b/Libraries/Animated/src/nodes/AnimatedInterpolation.js @@ -242,11 +242,10 @@ function createInterpolationFromStringOutputRange( // -> // 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...' return outputRange[0].replace(stringShapeRegex, () => { - let val = +interpolations[i++](input); - if (shouldRound) { - val = i < 4 ? Math.round(val) : Math.round(val * 1000) / 1000; - } - return String(val); + const val = +interpolations[i++](input); + const rounded = + shouldRound && i < 4 ? Math.round(val) : Math.round(val * 1000) / 1000; + return String(rounded); }); }; } diff --git a/Libraries/Animated/src/nodes/AnimatedNode.js b/Libraries/Animated/src/nodes/AnimatedNode.js index 5b1664bb8..1d670f18a 100644 --- a/Libraries/Animated/src/nodes/AnimatedNode.js +++ b/Libraries/Animated/src/nodes/AnimatedNode.js @@ -35,18 +35,12 @@ class AnimatedNode { /* Methods and props used by native Animated impl */ __isNative: boolean; - __isConnected: boolean; __nativeTag: ?number; __makeNative() { if (!this.__isNative) { throw new Error('This node cannot be made a "native" animated node'); } } - __connectAnimatedNodes() { - if (!this.__isNative) { - throw new Error('This node cannot be connected natively'); - } - } __getNativeTag(): ?number { NativeAnimatedHelper.assertNativeAnimatedModule(); invariant( @@ -55,11 +49,11 @@ class AnimatedNode { ); if (this.__nativeTag == null) { const nativeTag: ?number = NativeAnimatedHelper.generateNewNodeTag(); - this.__nativeTag = nativeTag; NativeAnimatedHelper.API.createAnimatedNode( nativeTag, this.__getNativeConfig(), ); + this.__nativeTag = nativeTag; } return this.__nativeTag; } diff --git a/Libraries/Animated/src/nodes/AnimatedProps.js b/Libraries/Animated/src/nodes/AnimatedProps.js index 462949bec..be3dfd86d 100644 --- a/Libraries/Animated/src/nodes/AnimatedProps.js +++ b/Libraries/Animated/src/nodes/AnimatedProps.js @@ -151,7 +151,6 @@ class AnimatedProps extends AnimatedNode { for (const propKey in this._props) { const value = this._props[propKey]; if (value instanceof AnimatedNode) { - value.__makeNative(); propsConfig[propKey] = value.__getNativeTag(); } } diff --git a/Libraries/Animated/src/nodes/AnimatedStyle.js b/Libraries/Animated/src/nodes/AnimatedStyle.js index 3ab591d29..e1f3d332a 100644 --- a/Libraries/Animated/src/nodes/AnimatedStyle.js +++ b/Libraries/Animated/src/nodes/AnimatedStyle.js @@ -108,9 +108,7 @@ class AnimatedStyle extends AnimatedWithChildren { const styleConfig = {}; for (const styleKey in this._style) { if (this._style[styleKey] instanceof AnimatedNode) { - const style = this._style[styleKey]; - style.__makeNative(); - styleConfig[styleKey] = style.__getNativeTag(); + styleConfig[styleKey] = this._style[styleKey].__getNativeTag(); } // Non-animated styles are set using `setNativeProps`, no need // to pass those as a part of the node config diff --git a/Libraries/Animated/src/nodes/AnimatedWithChildren.js b/Libraries/Animated/src/nodes/AnimatedWithChildren.js index 5c3c575ca..3940c4ae2 100644 --- a/Libraries/Animated/src/nodes/AnimatedWithChildren.js +++ b/Libraries/Animated/src/nodes/AnimatedWithChildren.js @@ -25,15 +25,6 @@ class AnimatedWithChildren extends AnimatedNode { this.__isNative = true; for (const child of this._children) { child.__makeNative(); - } - } - } - - __connectAnimatedNodes() { - if (!this.__isConnected) { - this.__isConnected = true; - for (const child of this._children) { - child.__connectAnimatedNodes(); NativeAnimatedHelper.API.connectAnimatedNodes( this.__getNativeTag(), child.__getNativeTag(), diff --git a/Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m index 5fbac0716..0fbaf57d4 100644 --- a/Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m +++ b/Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m @@ -9,89 +9,27 @@ #import "RCTAnimationUtils.h" -static NSRegularExpression *regex; - @implementation RCTInterpolationAnimatedNode { __weak RCTValueAnimatedNode *_parentNode; NSArray *_inputRange; NSArray *_outputRange; - NSArray *> *_outputs; - NSArray *_soutputRange; NSString *_extrapolateLeft; NSString *_extrapolateRight; - NSUInteger _numVals; - bool _hasStringOutput; - bool _shouldRound; - NSArray *_matches; } - (instancetype)initWithTag:(NSNumber *)tag config:(NSDictionary *)config { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - regex = [NSRegularExpression regularExpressionWithPattern:@"[0-9.-]+" options:NSRegularExpressionCaseInsensitive error:nil]; - }); if ((self = [super initWithTag:tag config:config])) { _inputRange = [config[@"inputRange"] copy]; NSMutableArray *outputRange = [NSMutableArray array]; - NSMutableArray *soutputRange = [NSMutableArray array]; - NSMutableArray *> *_outputRanges = [NSMutableArray array]; - - _hasStringOutput = NO; for (id value in config[@"outputRange"]) { if ([value isKindOfClass:[NSNumber class]]) { [outputRange addObject:value]; - } else if ([value isKindOfClass:[NSString class]]) { - /** - * Supports string shapes by extracting numbers so new values can be computed, - * and recombines those values into new strings of the same shape. Supports - * things like: - * - * rgba(123, 42, 99, 0.36) // colors - * -45deg // values with units - */ - NSMutableArray *output = [NSMutableArray array]; - [_outputRanges addObject:output]; - [soutputRange addObject:value]; - - _matches = [regex matchesInString:value options:0 range:NSMakeRange(0, [value length])]; - for (NSTextCheckingResult *match in _matches) { - NSString* strNumber = [value substringWithRange:match.range]; - [output addObject:[NSNumber numberWithDouble:strNumber.doubleValue]]; - } - - _hasStringOutput = YES; - [outputRange addObject:[output objectAtIndex:0]]; } } - if (_hasStringOutput) { - // ['rgba(0, 100, 200, 0)', 'rgba(50, 150, 250, 0.5)'] - // -> - // [ - // [0, 50], - // [100, 150], - // [200, 250], - // [0, 0.5], - // ] - _numVals = [_matches count]; - NSString *value = [soutputRange objectAtIndex:0]; - _shouldRound = [value containsString:@"rgb"]; - _matches = [regex matchesInString:value options:0 range:NSMakeRange(0, [value length])]; - NSMutableArray *> *outputs = [NSMutableArray arrayWithCapacity:_numVals]; - NSUInteger size = [soutputRange count]; - for (NSUInteger j = 0; j < _numVals; j++) { - NSMutableArray *output = [NSMutableArray arrayWithCapacity:size]; - [outputs addObject:output]; - for (int i = 0; i < size; i++) { - [output addObject:[[_outputRanges objectAtIndex:i] objectAtIndex:j]]; - } - } - _outputs = [outputs copy]; - } _outputRange = [outputRange copy]; - _soutputRange = [soutputRange copy]; _extrapolateLeft = config[@"extrapolateLeft"]; _extrapolateRight = config[@"extrapolateRight"]; } @@ -123,47 +61,11 @@ static NSRegularExpression *regex; CGFloat inputValue = _parentNode.value; - CGFloat interpolated = RCTInterpolateValueInRange(inputValue, - _inputRange, - _outputRange, - _extrapolateLeft, - _extrapolateRight); - self.value = interpolated; - if (_hasStringOutput) { - // 'rgba(0, 100, 200, 0)' - // -> - // 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...' - if (_numVals > 1) { - NSString *text = _soutputRange[0]; - NSMutableString *formattedText = [NSMutableString stringWithString:text]; - NSUInteger i = _numVals; - for (NSTextCheckingResult *match in [_matches reverseObjectEnumerator]) { - CGFloat val = RCTInterpolateValueInRange(inputValue, - _inputRange, - _outputs[--i], - _extrapolateLeft, - _extrapolateRight); - NSString *str; - if (_shouldRound) { - // rgba requires that the r,g,b are integers.... so we want to round them, but we *dont* want to - // round the opacity (4th column). - bool isAlpha = i == 3; - CGFloat rounded = isAlpha ? round(val * 1000) / 1000 : round(val); - str = isAlpha ? [NSString stringWithFormat:@"%1.3f", rounded] : [NSString stringWithFormat:@"%1.0f", rounded]; - } else { - str = [NSString stringWithFormat:@"%1f", val]; - } - - [formattedText replaceCharactersInRange:[match range] withString:str]; - } - self.animatedObject = formattedText; - } else { - self.animatedObject = [regex stringByReplacingMatchesInString:_soutputRange[0] - options:0 - range:NSMakeRange(0, _soutputRange[0].length) - withTemplate:[NSString stringWithFormat:@"%1f", interpolated]]; - } - } + self.value = RCTInterpolateValueInRange(inputValue, + _inputRange, + _outputRange, + _extrapolateLeft, + _extrapolateRight); } @end diff --git a/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m index 07a36cefe..1b8e3e16f 100644 --- a/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m +++ b/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m @@ -110,13 +110,8 @@ } else if ([parentNode isKindOfClass:[RCTValueAnimatedNode class]]) { NSString *property = [self propertyNameForParentTag:parentTag]; - id animatedObject = [(RCTValueAnimatedNode *)parentNode animatedObject]; - if (animatedObject) { - self->_propsDictionary[property] = animatedObject; - } else { - CGFloat value = [(RCTValueAnimatedNode *)parentNode value]; - self->_propsDictionary[property] = @(value); - } + CGFloat value = [(RCTValueAnimatedNode *)parentNode value]; + self->_propsDictionary[property] = @(value); } } diff --git a/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h b/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h index c46d392ca..53b5da380 100644 --- a/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h +++ b/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h @@ -24,7 +24,6 @@ - (void)extractOffset; @property (nonatomic, assign) CGFloat value; -@property (nonatomic, strong) id animatedObject; @property (nonatomic, weak) id valueObserver; @end diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java index 2f7f3616b..0b91c3781 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java @@ -9,12 +9,6 @@ package com.facebook.react.animated; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.ReadableType; - -import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import javax.annotation.Nullable; /** @@ -27,7 +21,6 @@ import javax.annotation.Nullable; public static final String EXTRAPOLATE_TYPE_IDENTITY = "identity"; public static final String EXTRAPOLATE_TYPE_CLAMP = "clamp"; public static final String EXTRAPOLATE_TYPE_EXTEND = "extend"; - static final Pattern regex = Pattern.compile("[0-9.-]+"); private static double[] fromDoubleArray(ReadableArray ary) { double[] res = new double[ary.size()]; @@ -112,68 +105,13 @@ import javax.annotation.Nullable; private final double mInputRange[]; private final double mOutputRange[]; - private String mPattern; - private double mOutputs[][]; - private final boolean mHasStringOutput; - private final Matcher mSOutputMatcher; private final String mExtrapolateLeft; private final String mExtrapolateRight; private @Nullable ValueAnimatedNode mParent; - private boolean mShouldRound; - private int mNumVals; public InterpolationAnimatedNode(ReadableMap config) { mInputRange = fromDoubleArray(config.getArray("inputRange")); - ReadableArray output = config.getArray("outputRange"); - mHasStringOutput = output.getType(0) == ReadableType.String; - if (mHasStringOutput) { - /* - * Supports string shapes by extracting numbers so new values can be computed, - * and recombines those values into new strings of the same shape. Supports - * things like: - * - * rgba(123, 42, 99, 0.36) // colors - * -45deg // values with units - */ - int size = output.size(); - mOutputRange = new double[size]; - mPattern = output.getString(0); - mShouldRound = mPattern.startsWith("rgb"); - mSOutputMatcher = regex.matcher(mPattern); - ArrayList> mOutputRanges = new ArrayList<>(); - for (int i = 0; i < size; i++) { - String val = output.getString(i); - Matcher m = regex.matcher(val); - ArrayList outputRange = new ArrayList<>(); - mOutputRanges.add(outputRange); - while (m.find()) { - Double parsed = Double.parseDouble(m.group()); - outputRange.add(parsed); - } - mOutputRange[i] = outputRange.get(0); - } - - // ['rgba(0, 100, 200, 0)', 'rgba(50, 150, 250, 0.5)'] - // -> - // [ - // [0, 50], - // [100, 150], - // [200, 250], - // [0, 0.5], - // ] - mNumVals = mOutputRanges.get(0).size(); - mOutputs = new double[mNumVals][]; - for (int j = 0; j < mNumVals; j++) { - double[] arr = new double[size]; - mOutputs[j] = arr; - for (int i = 0; i < size; i++) { - arr[i] = mOutputRanges.get(i).get(j); - } - } - } else { - mOutputRange = fromDoubleArray(output); - mSOutputMatcher = null; - } + mOutputRange = fromDoubleArray(config.getArray("outputRange")); mExtrapolateLeft = config.getString("extrapolateLeft"); mExtrapolateRight = config.getString("extrapolateRight"); } @@ -204,33 +142,6 @@ import javax.annotation.Nullable; // unattached node. return; } - double value = mParent.getValue(); - mValue = interpolate(value, mInputRange, mOutputRange, mExtrapolateLeft, mExtrapolateRight); - if (mHasStringOutput) { - // 'rgba(0, 100, 200, 0)' - // -> - // 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...' - if (mNumVals > 1) { - StringBuffer sb = new StringBuffer(mPattern.length()); - int i = 0; - mSOutputMatcher.reset(); - while (mSOutputMatcher.find()) { - double val = interpolate(value, mInputRange, mOutputs[i++], mExtrapolateLeft, mExtrapolateRight); - if (mShouldRound) { - // rgba requires that the r,g,b are integers.... so we want to round them, but we *dont* want to - // round the opacity (4th column). - boolean isAlpha = i == 4; - int rounded = (int)Math.round(isAlpha ? val * 1000 : val); - mSOutputMatcher.appendReplacement(sb, isAlpha ? String.valueOf((double)rounded / 1000) : String.valueOf(rounded)); - } else { - mSOutputMatcher.appendReplacement(sb, String.valueOf(val)); - } - } - mSOutputMatcher.appendTail(sb); - mAnimatedObject = sb.toString(); - } else { - mAnimatedObject = mSOutputMatcher.replaceFirst(String.valueOf(mValue)); - } - } + mValue = interpolate(mParent.getValue(), mInputRange, mOutputRange, mExtrapolateLeft, mExtrapolateRight); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java index 7bb7eaaeb..250eb21db 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java @@ -84,12 +84,7 @@ import javax.annotation.Nullable; } else if (node instanceof StyleAnimatedNode) { ((StyleAnimatedNode) node).collectViewUpdates(mPropMap); } else if (node instanceof ValueAnimatedNode) { - Object animatedObject = ((ValueAnimatedNode) node).getAnimatedObject(); - if (animatedObject instanceof String) { - mPropMap.putString(entry.getKey(), (String)animatedObject); - } else { - mPropMap.putDouble(entry.getKey(), ((ValueAnimatedNode) node).getValue()); - } + mPropMap.putDouble(entry.getKey(), ((ValueAnimatedNode) node).getValue()); } else { throw new IllegalArgumentException("Unsupported type of node used in property node " + node.getClass()); diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java index 0c92f11f8..49426c77e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java @@ -16,7 +16,6 @@ import javax.annotation.Nullable; * library. */ /*package*/ class ValueAnimatedNode extends AnimatedNode { - /*package*/ Object mAnimatedObject = null; /*package*/ double mValue = Double.NaN; /*package*/ double mOffset = 0; private @Nullable AnimatedNodeValueListener mValueListener; @@ -34,10 +33,6 @@ import javax.annotation.Nullable; return mOffset + mValue; } - public Object getAnimatedObject() { - return mAnimatedObject; - } - public void flattenOffset() { mValue += mOffset; mOffset = 0;