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
This commit is contained in:
Christoph Nakazawa
2019-03-26 17:07:34 -07:00
committed by Facebook Github Bot
parent 58cd20459f
commit 95c7db90b8
13 changed files with 18 additions and 240 deletions

View File

@@ -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;
}
}

View File

@@ -57,7 +57,6 @@ class Animation {
}
__startNativeAnimation(animatedValue: AnimatedValue): void {
animatedValue.__makeNative();
animatedValue.__connectAnimatedNodes();
this.__nativeId = NativeAnimatedHelper.generateNewAnimationId();
NativeAnimatedHelper.API.startAnimatingNode(
this.__nativeId,

View File

@@ -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);
});
};
}

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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(),

View File

@@ -9,89 +9,27 @@
#import "RCTAnimationUtils.h"
static NSRegularExpression *regex;
@implementation RCTInterpolationAnimatedNode
{
__weak RCTValueAnimatedNode *_parentNode;
NSArray<NSNumber *> *_inputRange;
NSArray<NSNumber *> *_outputRange;
NSArray<NSArray<NSNumber *> *> *_outputs;
NSArray<NSString *> *_soutputRange;
NSString *_extrapolateLeft;
NSString *_extrapolateRight;
NSUInteger _numVals;
bool _hasStringOutput;
bool _shouldRound;
NSArray<NSTextCheckingResult*> *_matches;
}
- (instancetype)initWithTag:(NSNumber *)tag
config:(NSDictionary<NSString *, id> *)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<NSMutableArray<NSNumber *> *> *_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<NSMutableArray<NSNumber *> *> *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

View File

@@ -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);
}
}

View File

@@ -24,7 +24,6 @@
- (void)extractOffset;
@property (nonatomic, assign) CGFloat value;
@property (nonatomic, strong) id animatedObject;
@property (nonatomic, weak) id<RCTValueAnimatedNodeObserver> valueObserver;
@end

View File

@@ -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<ArrayList<Double>> mOutputRanges = new ArrayList<>();
for (int i = 0; i < size; i++) {
String val = output.getString(i);
Matcher m = regex.matcher(val);
ArrayList<Double> 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);
}
}

View File

@@ -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());

View File

@@ -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;