Add support for clamping for NativeAnimated on iOS

Summary:
This diff adds support for clamping on iOS. It separates out code originally submitted in #9048.

Test plan (required)

Run UIExplorer NativeAnimated examples before and after - compare the results. Pay special attention to the new clamped spring example.
Closes https://github.com/facebook/react-native/pull/9625

Differential Revision: D4053231

fbshipit-source-id: 29048de444ff5f6d7fe7dce7897399b483ee6d2d
This commit is contained in:
Ryan Gomba 2016-10-20 14:12:37 -07:00 committed by Facebook Github Bot
parent 518915a750
commit 5794ff61bc
5 changed files with 70 additions and 21 deletions

View File

@ -320,7 +320,7 @@ exports.examples = [
}, },
}, },
{ {
title: 'Scale interpolation', title: 'Scale interpolation with clamping',
description: 'description', description: 'description',
render: function() { render: function() {
return ( return (
@ -335,8 +335,9 @@ exports.examples = [
transform: [ transform: [
{ {
scale: anim.interpolate({ scale: anim.interpolate({
inputRange: [0, 1], inputRange: [0, 0.5],
outputRange: [1, 1.4], outputRange: [1, 1.4],
extrapolateRight: 'clamp',
}) })
} }
], ],

View File

@ -118,14 +118,23 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
fromInterval, fromInterval,
toInterval, toInterval,
fromFrameValue.doubleValue, fromFrameValue.doubleValue,
toFrameValue.doubleValue); toFrameValue.doubleValue,
EXTRAPOLATE_TYPE_EXTEND,
EXTRAPOLATE_TYPE_EXTEND);
[self updateOutputWithFrameOutput:frameOutput]; [self updateOutputWithFrameOutput:frameOutput];
} }
- (void)updateOutputWithFrameOutput:(CGFloat)frameOutput - (void)updateOutputWithFrameOutput:(CGFloat)frameOutput
{ {
CGFloat outputValue = RCTInterpolateValue(frameOutput, 0, 1, _fromValue, _toValue); CGFloat outputValue = RCTInterpolateValue(frameOutput,
0,
1,
_fromValue,
_toValue,
EXTRAPOLATE_TYPE_EXTEND,
EXTRAPOLATE_TYPE_EXTEND);
_outputValue = @(outputValue); _outputValue = @(outputValue);
_valueNode.value = outputValue; _valueNode.value = outputValue;
[_valueNode setNeedsUpdate]; [_valueNode setNeedsUpdate];

View File

@ -15,6 +15,8 @@
__weak RCTValueAnimatedNode *_parentNode; __weak RCTValueAnimatedNode *_parentNode;
NSArray<NSNumber *> *_inputRange; NSArray<NSNumber *> *_inputRange;
NSArray<NSNumber *> *_outputRange; NSArray<NSNumber *> *_outputRange;
NSString *_extrapolateLeft;
NSString *_extrapolateRight;
} }
- (instancetype)initWithTag:(NSNumber *)tag - (instancetype)initWithTag:(NSNumber *)tag
@ -29,6 +31,8 @@
} }
} }
_outputRange = [outputRange copy]; _outputRange = [outputRange copy];
_extrapolateLeft = config[@"extrapolateLeft"];
_extrapolateRight = config[@"extrapolateRight"];
} }
return self; return self;
} }
@ -70,19 +74,20 @@
return; return;
} }
NSUInteger rangeIndex = [self findIndexOfNearestValue:_parentNode.value CGFloat inputValue = _parentNode.value;
inRange:_inputRange]; NSUInteger rangeIndex = [self findIndexOfNearestValue:inputValue inRange:_inputRange];
NSNumber *inputMin = _inputRange[rangeIndex]; NSNumber *inputMin = _inputRange[rangeIndex];
NSNumber *inputMax = _inputRange[rangeIndex + 1]; NSNumber *inputMax = _inputRange[rangeIndex + 1];
NSNumber *outputMin = _outputRange[rangeIndex]; NSNumber *outputMin = _outputRange[rangeIndex];
NSNumber *outputMax = _outputRange[rangeIndex + 1]; NSNumber *outputMax = _outputRange[rangeIndex + 1];
CGFloat outputValue = RCTInterpolateValue(_parentNode.value, self.value = RCTInterpolateValue(inputValue,
inputMin.doubleValue, inputMin.doubleValue,
inputMax.doubleValue, inputMax.doubleValue,
outputMin.doubleValue, outputMin.doubleValue,
outputMax.doubleValue); outputMax.doubleValue,
self.value = outputValue; _extrapolateLeft,
_extrapolateRight);
} }
@end @end

View File

@ -12,11 +12,17 @@
#import "RCTDefines.h" #import "RCTDefines.h"
static NSString * const EXTRAPOLATE_TYPE_IDENTITY = @"identity";
static NSString * const EXTRAPOLATE_TYPE_CLAMP = @"clamp";
static NSString * const EXTRAPOLATE_TYPE_EXTEND = @"extend";
RCT_EXTERN CGFloat RCTInterpolateValue(CGFloat value, RCT_EXTERN CGFloat RCTInterpolateValue(CGFloat value,
CGFloat fromMin, CGFloat inputMin,
CGFloat fromMax, CGFloat inputMax,
CGFloat toMin, CGFloat outputMin,
CGFloat toMax); CGFloat outputMax,
NSString *extrapolateLeft,
NSString *extrapolateRight);
RCT_EXTERN CGFloat RCTRadiansToDegrees(CGFloat radians); RCT_EXTERN CGFloat RCTRadiansToDegrees(CGFloat radians);
RCT_EXTERN CGFloat RCTDegreesToRadians(CGFloat degrees); RCT_EXTERN CGFloat RCTDegreesToRadians(CGFloat degrees);

View File

@ -9,16 +9,44 @@
#import "RCTAnimationUtils.h" #import "RCTAnimationUtils.h"
#import "RCTLog.h"
/** /**
* Interpolates value by remapping it linearly fromMin->fromMax to toMin->toMax * Interpolates value by remapping it linearly fromMin->fromMax to toMin->toMax
*/ */
CGFloat RCTInterpolateValue(CGFloat value, CGFloat RCTInterpolateValue(CGFloat value,
CGFloat fromMin, CGFloat inputMin,
CGFloat fromMax, CGFloat inputMax,
CGFloat toMin, CGFloat outputMin,
CGFloat toMax) CGFloat outputMax,
NSString *extrapolateLeft,
NSString *extrapolateRight)
{ {
return toMin + (value - fromMin) * (toMax - toMin) / (fromMax - fromMin); if (value < inputMin) {
if ([extrapolateLeft isEqualToString:EXTRAPOLATE_TYPE_IDENTITY]) {
return value;
} else if ([extrapolateLeft isEqualToString:EXTRAPOLATE_TYPE_CLAMP]) {
value = inputMin;
} else if ([extrapolateLeft isEqualToString:EXTRAPOLATE_TYPE_EXTEND]) {
// noop
} else {
RCTLogError(@"Invalid extrapolation type %@ for left extrapolation", extrapolateLeft);
}
}
if (value > inputMax) {
if ([extrapolateRight isEqualToString:EXTRAPOLATE_TYPE_IDENTITY]) {
return value;
} else if ([extrapolateRight isEqualToString:EXTRAPOLATE_TYPE_CLAMP]) {
value = inputMax;
} else if ([extrapolateRight isEqualToString:EXTRAPOLATE_TYPE_EXTEND]) {
// noop
} else {
RCTLogError(@"Invalid extrapolation type %@ for right extrapolation", extrapolateRight);
}
}
return outputMin + (value - inputMin) * (outputMax - outputMin) / (inputMax - inputMin);
} }
CGFloat RCTRadiansToDegrees(CGFloat radians) CGFloat RCTRadiansToDegrees(CGFloat radians)