Add an implementation of Animated.subtract
Summary: Fixes #18451 I've added another example to NativeAnimationsExample, which makes use of `Animated.substract()`, let me know if the example is not desired / doesn't add much value. Below two GIFs of the new method working on iOS and Android: <img width="320" src="https://user-images.githubusercontent.com/1437605/38154748-165cc5f8-3474-11e8-8b31-504444271896.gif" /> <img width="320" src="https://user-images.githubusercontent.com/1437605/38154749-1679bff0-3474-11e8-80b1-b558d44e0494.gif" /> <!-- Required: Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work. Bonus points for screenshots and videos! --> https://github.com/facebook/react-native-website/pull/276 [GENERAL] [ENHANCEMENT] [Animated] - Implemented Animated.subtract Closes https://github.com/facebook/react-native/pull/18630 Differential Revision: D7462867 Pulled By: hramos fbshipit-source-id: 4cb0b8af08bb0c841e44ea2099889b8c02a22a4a
This commit is contained in:
parent
1f27098a1a
commit
4906f8d28c
|
@ -20,6 +20,7 @@ const AnimatedModulo = require('./nodes/AnimatedModulo');
|
|||
const AnimatedMultiplication = require('./nodes/AnimatedMultiplication');
|
||||
const AnimatedNode = require('./nodes/AnimatedNode');
|
||||
const AnimatedProps = require('./nodes/AnimatedProps');
|
||||
const AnimatedSubtraction = require('./nodes/AnimatedSubtraction');
|
||||
const AnimatedTracking = require('./nodes/AnimatedTracking');
|
||||
const AnimatedValue = require('./nodes/AnimatedValue');
|
||||
const AnimatedValueXY = require('./nodes/AnimatedValueXY');
|
||||
|
@ -54,6 +55,13 @@ const add = function(
|
|||
return new AnimatedAddition(a, b);
|
||||
};
|
||||
|
||||
const subtract = function(
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number,
|
||||
): AnimatedSubtraction {
|
||||
return new AnimatedSubtraction(a, b);
|
||||
};
|
||||
|
||||
const divide = function(
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number,
|
||||
|
@ -568,6 +576,14 @@ module.exports = {
|
|||
*/
|
||||
add,
|
||||
|
||||
/**
|
||||
* Creates a new Animated value composed by subtracting the second Animated
|
||||
* value from the first Animated value.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animated.html#subtract
|
||||
*/
|
||||
subtract,
|
||||
|
||||
/**
|
||||
* Creates a new Animated value composed by dividing the first Animated value
|
||||
* by the second Animated value.
|
||||
|
|
|
@ -333,6 +333,38 @@ describe('Native Animated', () => {
|
|||
.toBeCalledWith(additionCall[1].input[1], {type: 'value', value: 2, offset: 0});
|
||||
});
|
||||
|
||||
it('sends a valid graph description for Animated.subtract nodes', () => {
|
||||
const first = new Animated.Value(2);
|
||||
const second = new Animated.Value(1);
|
||||
first.__makeNative();
|
||||
second.__makeNative();
|
||||
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: Animated.subtract(first, second),
|
||||
},
|
||||
});
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'subtraction', input: expect.any(Array)},
|
||||
);
|
||||
const subtractionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
(call) => call[1].type === 'subtraction'
|
||||
);
|
||||
expect(subtractionCalls.length).toBe(1);
|
||||
const subtractionCall = subtractionCalls[0];
|
||||
const subtractionNodeTag = subtractionCall[0];
|
||||
const subtractionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
(call) => call[1] === subtractionNodeTag
|
||||
);
|
||||
expect(subtractionConnectionCalls.length).toBe(2);
|
||||
expect(nativeAnimatedModule.createAnimatedNode)
|
||||
.toBeCalledWith(subtractionCall[1].input[0], {type: 'value', value: 2, offset: 0});
|
||||
expect(nativeAnimatedModule.createAnimatedNode)
|
||||
.toBeCalledWith(subtractionCall[1].input[1], {type: 'value', value: 1, offset: 0});
|
||||
});
|
||||
|
||||
it('sends a valid graph description for Animated.multiply nodes', () => {
|
||||
const first = new Animated.Value(2);
|
||||
const second = new Animated.Value(1);
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule AnimatedSubtraction
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AnimatedInterpolation = require('./AnimatedInterpolation');
|
||||
const AnimatedNode = require('./AnimatedNode');
|
||||
const AnimatedValue = require('./AnimatedValue');
|
||||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
|
||||
import type {InterpolationConfigType} from './AnimatedInterpolation';
|
||||
|
||||
class AnimatedSubtraction extends AnimatedWithChildren {
|
||||
_a: AnimatedNode;
|
||||
_b: AnimatedNode;
|
||||
|
||||
constructor(a: AnimatedNode | number, b: AnimatedNode | number) {
|
||||
super();
|
||||
this._a = typeof a === 'number' ? new AnimatedValue(a) : a;
|
||||
this._b = typeof b === 'number' ? new AnimatedValue(b) : b;
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
this._a.__makeNative();
|
||||
this._b.__makeNative();
|
||||
super.__makeNative();
|
||||
}
|
||||
|
||||
__getValue(): number {
|
||||
return this._a.__getValue() - this._b.__getValue();
|
||||
}
|
||||
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
this._a.__addChild(this);
|
||||
this._b.__addChild(this);
|
||||
}
|
||||
|
||||
__detach(): void {
|
||||
this._a.__removeChild(this);
|
||||
this._b.__removeChild(this);
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
return {
|
||||
type: 'subtraction',
|
||||
input: [this._a.__getNativeTag(), this._b.__getNativeTag()],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedSubtraction;
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
|
||||
@interface RCTSubtractionAnimatedNode : RCTValueAnimatedNode
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "RCTSubtractionAnimatedNode.h"
|
||||
|
||||
@implementation RCTSubtractionAnimatedNode
|
||||
|
||||
- (void)performUpdate
|
||||
{
|
||||
[super performUpdate];
|
||||
NSArray<NSNumber *> *inputNodes = self.config[@"input"];
|
||||
if (inputNodes.count > 1) {
|
||||
RCTValueAnimatedNode *parent1 = (RCTValueAnimatedNode *)[self.parentNodes objectForKey:inputNodes[0]];
|
||||
RCTValueAnimatedNode *parent2 = (RCTValueAnimatedNode *)[self.parentNodes objectForKey:inputNodes[1]];
|
||||
if ([parent1 isKindOfClass:[RCTValueAnimatedNode class]] &&
|
||||
[parent2 isKindOfClass:[RCTValueAnimatedNode class]]) {
|
||||
self.value = parent1.value - parent2.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -111,6 +111,7 @@
|
|||
2D3B5EFE1D9B0B4800451313 /* RCTStyleAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E31D07A6C9005F35D8 /* RCTStyleAnimatedNode.m */; };
|
||||
2D3B5EFF1D9B0B4800451313 /* RCTTransformAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E51D07A6C9005F35D8 /* RCTTransformAnimatedNode.m */; };
|
||||
2D3B5F001D9B0B4800451313 /* RCTValueAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E71D07A6C9005F35D8 /* RCTValueAnimatedNode.m */; };
|
||||
2EC00631206EA19300586E91 /* RCTSubtractionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EC00630206EA19300586E91 /* RCTSubtractionAnimatedNode.m */; };
|
||||
44DB7D942024F74200588FCD /* RCTTrackingAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 44DB7D932024F74200588FCD /* RCTTrackingAnimatedNode.h */; };
|
||||
44DB7D952024F74200588FCD /* RCTTrackingAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 44DB7D932024F74200588FCD /* RCTTrackingAnimatedNode.h */; };
|
||||
44DB7D972024F75100588FCD /* RCTTrackingAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 44DB7D962024F75100588FCD /* RCTTrackingAnimatedNode.m */; };
|
||||
|
@ -213,6 +214,8 @@
|
|||
19F00F201DC8847500113FEE /* RCTEventAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTEventAnimation.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
19F00F211DC8847500113FEE /* RCTEventAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTEventAnimation.m; sourceTree = "<group>"; };
|
||||
2D2A28201D9B03D100D4039D /* libRCTAnimation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTAnimation.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2EC0062F206EA15F00586E91 /* RCTSubtractionAnimatedNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTSubtractionAnimatedNode.h; sourceTree = "<group>"; };
|
||||
2EC00630206EA19300586E91 /* RCTSubtractionAnimatedNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTSubtractionAnimatedNode.m; sourceTree = "<group>"; };
|
||||
44DB7D932024F74200588FCD /* RCTTrackingAnimatedNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTTrackingAnimatedNode.h; sourceTree = "<group>"; };
|
||||
44DB7D962024F75100588FCD /* RCTTrackingAnimatedNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTTrackingAnimatedNode.m; sourceTree = "<group>"; };
|
||||
5C9894931D999639008027DB /* RCTDivisionAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTDivisionAnimatedNode.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
|
@ -246,6 +249,8 @@
|
|||
193F64F31D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m */,
|
||||
13E501D61D07A6C9005F35D8 /* RCTAdditionAnimatedNode.h */,
|
||||
13E501D71D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m */,
|
||||
2EC0062F206EA15F00586E91 /* RCTSubtractionAnimatedNode.h */,
|
||||
2EC00630206EA19300586E91 /* RCTSubtractionAnimatedNode.m */,
|
||||
13E501D81D07A6C9005F35D8 /* RCTAnimatedNode.h */,
|
||||
13E501D91D07A6C9005F35D8 /* RCTAnimatedNode.m */,
|
||||
13E501DC1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.h */,
|
||||
|
@ -483,6 +488,7 @@
|
|||
5C9894951D999639008027DB /* RCTDivisionAnimatedNode.m in Sources */,
|
||||
13E501EF1D07A6C9005F35D8 /* RCTTransformAnimatedNode.m in Sources */,
|
||||
194804EE1E975D8E00623005 /* RCTDecayAnimation.m in Sources */,
|
||||
2EC00631206EA19300586E91 /* RCTSubtractionAnimatedNode.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#import "RCTPropsAnimatedNode.h"
|
||||
#import "RCTSpringAnimation.h"
|
||||
#import "RCTStyleAnimatedNode.h"
|
||||
#import "RCTSubtractionAnimatedNode.h"
|
||||
#import "RCTTransformAnimatedNode.h"
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
#import "RCTTrackingAnimatedNode.h"
|
||||
|
@ -66,6 +67,7 @@
|
|||
@"division" : [RCTDivisionAnimatedNode class],
|
||||
@"multiplication" : [RCTMultiplicationAnimatedNode class],
|
||||
@"modulus" : [RCTModuloAnimatedNode class],
|
||||
@"subtraction" : [RCTSubtractionAnimatedNode class],
|
||||
@"transform" : [RCTTransformAnimatedNode class],
|
||||
@"tracking" : [RCTTrackingAnimatedNode class]};
|
||||
});
|
||||
|
|
|
@ -429,6 +429,48 @@ exports.examples = [
|
|||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Multistage With Subtract',
|
||||
render: function() {
|
||||
return (
|
||||
<Tester type="timing" config={{duration: 1000}}>
|
||||
{anim => (
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.block,
|
||||
{
|
||||
transform: [
|
||||
{
|
||||
translateX: anim.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0, 200],
|
||||
}),
|
||||
},
|
||||
{
|
||||
translateY: anim.interpolate({
|
||||
inputRange: [0, 0.5, 1],
|
||||
outputRange: [0, 50, 0],
|
||||
}),
|
||||
},
|
||||
],
|
||||
opacity: Animated.subtract(
|
||||
anim.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [1, 1],
|
||||
}),
|
||||
anim.interpolate({
|
||||
inputRange: [0, 0.5, 1],
|
||||
outputRange: [0, 0.5, 0],
|
||||
}),
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</Tester>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Scale interpolation with clamping',
|
||||
render: function() {
|
||||
|
|
|
@ -93,6 +93,8 @@ import javax.annotation.Nullable;
|
|||
node = new InterpolationAnimatedNode(config);
|
||||
} else if ("addition".equals(type)) {
|
||||
node = new AdditionAnimatedNode(config, this);
|
||||
} else if ("subtraction".equals(type)) {
|
||||
node = new SubtractionAnimatedNode(config, this);
|
||||
} else if ("division".equals(type)) {
|
||||
node = new DivisionAnimatedNode(config, this);
|
||||
} else if ("multiplication".equals(type)) {
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.animated;
|
||||
|
||||
import com.facebook.react.bridge.JSApplicationCausedNativeException;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
/**
|
||||
* Animated node that plays a role of value aggregator. It takes two or more value nodes as an input
|
||||
* and outputs a difference of values outputted by those nodes.
|
||||
*/
|
||||
/*package*/ class SubtractionAnimatedNode extends ValueAnimatedNode {
|
||||
|
||||
private final NativeAnimatedNodesManager mNativeAnimatedNodesManager;
|
||||
private final int[] mInputNodes;
|
||||
|
||||
public SubtractionAnimatedNode(
|
||||
ReadableMap config,
|
||||
NativeAnimatedNodesManager nativeAnimatedNodesManager) {
|
||||
mNativeAnimatedNodesManager = nativeAnimatedNodesManager;
|
||||
ReadableArray inputNodes = config.getArray("input");
|
||||
mInputNodes = new int[inputNodes.size()];
|
||||
for (int i = 0; i < mInputNodes.length; i++) {
|
||||
mInputNodes[i] = inputNodes.getInt(i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
for (int i = 0; i < mInputNodes.length; i++) {
|
||||
AnimatedNode animatedNode = mNativeAnimatedNodesManager.getNodeById(mInputNodes[i]);
|
||||
if (animatedNode != null && animatedNode instanceof ValueAnimatedNode) {
|
||||
double value = ((ValueAnimatedNode) animatedNode).getValue();
|
||||
if (i == 0) {
|
||||
mValue = value;
|
||||
continue;
|
||||
}
|
||||
mValue -= ((ValueAnimatedNode) animatedNode).getValue();
|
||||
} else {
|
||||
throw new JSApplicationCausedNativeException("Illegal node ID set as an input for " +
|
||||
"Animated.subtract node");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue