Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an implementation of Animated.subtract #18630

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Libraries/Animated/src/AnimatedImplementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down
32 changes: 32 additions & 0 deletions Libraries/Animated/src/__tests__/AnimatedNative-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
63 changes: 63 additions & 0 deletions Libraries/Animated/src/nodes/AnimatedSubtraction.js
Original file line number Diff line number Diff line change
@@ -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;
13 changes: 13 additions & 0 deletions Libraries/NativeAnimation/Nodes/RCTSubtractionAnimatedNode.h
Original file line number Diff line number Diff line change
@@ -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

27 changes: 27 additions & 0 deletions Libraries/NativeAnimation/Nodes/RCTSubtractionAnimatedNode.m
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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; };
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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;
};
Expand Down
2 changes: 2 additions & 0 deletions Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -66,6 +67,7 @@ - (void)createAnimatedNode:(nonnull NSNumber *)tag
@"division" : [RCTDivisionAnimatedNode class],
@"multiplication" : [RCTMultiplicationAnimatedNode class],
@"modulus" : [RCTModuloAnimatedNode class],
@"subtraction" : [RCTSubtractionAnimatedNode class],
@"transform" : [RCTTransformAnimatedNode class],
@"tracking" : [RCTTrackingAnimatedNode class]};
});
Expand Down
42 changes: 42 additions & 0 deletions RNTester/js/NativeAnimationsExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ public void createAnimatedNode(int tag, ReadableMap config) {
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)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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");
}
}
}
}