mirror of
https://github.com/status-im/react-native.git
synced 2025-01-14 03:26:07 +00:00
Add support for native animations on iOS
Summary: Currently on iOS animations are being performed on the JS thread. This ports animations over to the native thread and performs them natively. A lot of this work has already been done on Android, but this PR enables a few animation nodes that Android doesn't yet support such as Transform, Multiplication, and Addition nodes. Also there is a demo of the native animations added to the UIExplorer app. Closes https://github.com/facebook/react-native/pull/7884 Reviewed By: javache Differential Revision: D3409179 Pulled By: nicklockwood fbshipit-source-id: ef2d8840032e0c32f49e4a16ba86d448662e1751
This commit is contained in:
parent
9bdb63c234
commit
19e2388a76
308
Examples/UIExplorer/NativeAnimationsExample.js
Normal file
308
Examples/UIExplorer/NativeAnimationsExample.js
Normal file
@ -0,0 +1,308 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
View,
|
||||
Text,
|
||||
Animated,
|
||||
StyleSheet,
|
||||
TouchableWithoutFeedback,
|
||||
} = ReactNative;
|
||||
var UIExplorerButton = require('./UIExplorerButton');
|
||||
|
||||
var Tester = React.createClass({
|
||||
current: 0,
|
||||
getInitialState() {
|
||||
return {
|
||||
native: new Animated.Value(0),
|
||||
js: new Animated.Value(0),
|
||||
};
|
||||
},
|
||||
|
||||
onPress() {
|
||||
this.current = this.current ? 0 : 1;
|
||||
const config = {
|
||||
...this.props.config,
|
||||
toValue: this.current,
|
||||
};
|
||||
try {
|
||||
Animated[this.props.type](this.state.native, { ...config, useNativeDriver: true }).start();
|
||||
} catch (e) {
|
||||
// uncomment this if you want to get the redbox errors!
|
||||
throw e;
|
||||
}
|
||||
Animated[this.props.type](this.state.js, { ...config, useNativeDriver: false }).start();
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={this.onPress}>
|
||||
<View>
|
||||
<View>
|
||||
<Text>Native:</Text>
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
{this.props.children(this.state.native)}
|
||||
</View>
|
||||
<View>
|
||||
<Text>JavaScript:</Text>
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
{this.props.children(this.state.js)}
|
||||
</View>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
row: {
|
||||
padding: 10,
|
||||
zIndex: 1,
|
||||
},
|
||||
block: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
backgroundColor: 'blue',
|
||||
},
|
||||
});
|
||||
|
||||
exports.framework = 'React';
|
||||
exports.title = 'Native Animated Example';
|
||||
exports.description = 'Test out Native Animations';
|
||||
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'Multistage With Multiply and rotation',
|
||||
description: 'description',
|
||||
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],
|
||||
})
|
||||
},
|
||||
{
|
||||
rotate: anim.interpolate({
|
||||
inputRange: [0, 0.5, 1],
|
||||
outputRange: ['0deg', '90deg', '0deg'],
|
||||
})
|
||||
}
|
||||
],
|
||||
opacity: Animated.multiply(
|
||||
anim.interpolate({
|
||||
inputRange: [0,1],
|
||||
outputRange: [1,0]
|
||||
}), anim.interpolate({
|
||||
inputRange: [0,1],
|
||||
outputRange: [0.25,1]
|
||||
})
|
||||
)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</Tester>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Multistage With Multiply',
|
||||
description: 'description',
|
||||
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.multiply(
|
||||
anim.interpolate({
|
||||
inputRange: [0,1],
|
||||
outputRange: [1,0]
|
||||
}), anim.interpolate({
|
||||
inputRange: [0,1],
|
||||
outputRange: [0.25,1]
|
||||
})
|
||||
)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</Tester>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Scale interpolation',
|
||||
description: 'description',
|
||||
render: function() {
|
||||
return (
|
||||
<Tester
|
||||
type="timing"
|
||||
config={{ duration: 1000 }}
|
||||
>
|
||||
{anim => (
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.block,
|
||||
{
|
||||
transform: [
|
||||
{
|
||||
scale: anim.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [1, 1.4],
|
||||
})
|
||||
}
|
||||
],
|
||||
}
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</Tester>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Opacity without interpolation',
|
||||
description: 'description',
|
||||
render: function() {
|
||||
return (
|
||||
<Tester
|
||||
type="timing"
|
||||
config={{ duration: 1000 }}
|
||||
>
|
||||
{anim => (
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.block,
|
||||
{
|
||||
opacity: anim
|
||||
}
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</Tester>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Rotate interpolation',
|
||||
description: 'description',
|
||||
render: function() {
|
||||
return (
|
||||
<Tester
|
||||
type="timing"
|
||||
config={{ duration: 1000 }}
|
||||
>
|
||||
{anim => (
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.block,
|
||||
{
|
||||
transform: [
|
||||
{
|
||||
rotate: anim.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: ['0deg', '90deg'],
|
||||
})
|
||||
}
|
||||
],
|
||||
}
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</Tester>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'translateX => Animated.spring',
|
||||
description: 'description',
|
||||
render: function() {
|
||||
return (
|
||||
<Tester
|
||||
type="spring"
|
||||
config={{ bounciness: 0 }}
|
||||
>
|
||||
{anim => (
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.block,
|
||||
{
|
||||
transform: [
|
||||
{
|
||||
translateX: anim.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0, 100],
|
||||
})
|
||||
}
|
||||
],
|
||||
}
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</Tester>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
@ -32,6 +32,7 @@
|
||||
13BCE84F1C9C209600DD7AAD /* RCTComponentPropsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BCE84E1C9C209600DD7AAD /* RCTComponentPropsTests.m */; };
|
||||
13DB03481B5D2ED500C27245 /* RCTJSONTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 13DB03471B5D2ED500C27245 /* RCTJSONTests.m */; };
|
||||
13DF61B61B67A45000EDB188 /* RCTMethodArgumentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 13DF61B51B67A45000EDB188 /* RCTMethodArgumentTests.m */; };
|
||||
13E501F11D07A84A005F35D8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13E501A31D07A502005F35D8 /* libRCTAnimation.a */; };
|
||||
143BC5A11B21E45C00462512 /* UIExplorerSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 143BC5A01B21E45C00462512 /* UIExplorerSnapshotTests.m */; };
|
||||
144D21241B2204C5006DB32B /* RCTImageUtilTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 144D21231B2204C5006DB32B /* RCTImageUtilTests.m */; };
|
||||
147CED4C1AB3532B00DA3E4C /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 147CED4B1AB34F8C00DA3E4C /* libRCTActionSheet.a */; };
|
||||
@ -121,6 +122,13 @@
|
||||
remoteGlobalIDString = 3C86DF461ADF2C930047B81A;
|
||||
remoteInfo = RCTWebSocket;
|
||||
};
|
||||
13E501A21D07A502005F35D8 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 13E5019C1D07A502005F35D8 /* RCTAnimation.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 134814201AA4EA6300B7C361;
|
||||
remoteInfo = RCTAnimation;
|
||||
};
|
||||
143BC59B1B21E3E100462512 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
@ -210,6 +218,7 @@
|
||||
13CC9D481AEED2B90020D1C2 /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../../Libraries/Settings/RCTSettings.xcodeproj; sourceTree = "<group>"; };
|
||||
13DB03471B5D2ED500C27245 /* RCTJSONTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTJSONTests.m; sourceTree = "<group>"; };
|
||||
13DF61B51B67A45000EDB188 /* RCTMethodArgumentTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMethodArgumentTests.m; sourceTree = "<group>"; };
|
||||
13E5019C1D07A502005F35D8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = ../../Libraries/NativeAnimation/RCTAnimation.xcodeproj; sourceTree = "<group>"; };
|
||||
143BC57E1B21E18100462512 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
143BC5811B21E18100462512 /* testLayoutExampleSnapshot_1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testLayoutExampleSnapshot_1@2x.png"; sourceTree = "<group>"; };
|
||||
143BC5821B21E18100462512 /* testSliderExampleSnapshot_1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testSliderExampleSnapshot_1@2x.png"; sourceTree = "<group>"; };
|
||||
@ -285,6 +294,7 @@
|
||||
14AADF051AC3DBB1002390C9 /* libReact.a in Frameworks */,
|
||||
147CED4C1AB3532B00DA3E4C /* libRCTActionSheet.a in Frameworks */,
|
||||
134454601AAFCABD003F0779 /* libRCTAdSupport.a in Frameworks */,
|
||||
13E501F11D07A84A005F35D8 /* libRCTAnimation.a in Frameworks */,
|
||||
138DEE241B9EDFB6007F4EA5 /* libRCTCameraRoll.a in Frameworks */,
|
||||
134A8A2A1AACED7A00945AAE /* libRCTGeolocation.a in Frameworks */,
|
||||
13417FE91AA91432003F314A /* libRCTImage.a in Frameworks */,
|
||||
@ -315,6 +325,7 @@
|
||||
14AADEFF1AC3DB95002390C9 /* React.xcodeproj */,
|
||||
14E0EEC81AB118F7000DECC3 /* RCTActionSheet.xcodeproj */,
|
||||
134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */,
|
||||
13E5019C1D07A502005F35D8 /* RCTAnimation.xcodeproj */,
|
||||
138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */,
|
||||
134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */,
|
||||
13417FE31AA91428003F314A /* RCTImage.xcodeproj */,
|
||||
@ -413,6 +424,14 @@
|
||||
name = UIExplorer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
13E5019D1D07A502005F35D8 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13E501A31D07A502005F35D8 /* libRCTAnimation.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
143BC57C1B21E18100462512 /* UIExplorerUnitTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -693,6 +712,10 @@
|
||||
ProductGroup = 134454561AAFCAAE003F0779 /* Products */;
|
||||
ProjectRef = 134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 13E5019D1D07A502005F35D8 /* Products */;
|
||||
ProjectRef = 13E5019C1D07A502005F35D8 /* RCTAnimation.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 138DEE031B9EDDDB007F4EA5 /* Products */;
|
||||
ProjectRef = 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */;
|
||||
@ -801,6 +824,13 @@
|
||||
remoteRef = 139FDED81B0651EA00C62182 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
13E501A31D07A502005F35D8 /* libRCTAnimation.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRCTAnimation.a;
|
||||
remoteRef = 13E501A21D07A502005F35D8 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
147CED4B1AB34F8C00DA3E4C /* libRCTActionSheet.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0700"
|
||||
LastUpgradeVersion = "0730"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -68,6 +68,10 @@ const ComponentExamples: Array<UIExplorerExample> = [
|
||||
key: 'ModalExample',
|
||||
module: require('./ModalExample'),
|
||||
},
|
||||
{
|
||||
key: 'NativeAnimationsExample',
|
||||
module: require('./NativeAnimationsExample'),
|
||||
},
|
||||
{
|
||||
key: 'NavigatorExample',
|
||||
module: require('./Navigator/NavigatorExample'),
|
||||
|
@ -243,7 +243,7 @@ class TimingAnimation extends Animation {
|
||||
this._duration = config.duration !== undefined ? config.duration : 500;
|
||||
this._delay = config.delay !== undefined ? config.delay : 0;
|
||||
this.__isInteraction = config.isInteraction !== undefined ? config.isInteraction : true;
|
||||
this._useNativeDriver = !!config.useNativeDriver;
|
||||
this._useNativeDriver = config.useNativeDriver !== undefined ? config.useNativeDriver : false;
|
||||
}
|
||||
|
||||
_getNativeAnimationConfig(): any {
|
||||
@ -256,6 +256,7 @@ class TimingAnimation extends Animation {
|
||||
type: 'frames',
|
||||
frames,
|
||||
toValue: this._toValue,
|
||||
delay: this._delay
|
||||
};
|
||||
}
|
||||
|
||||
@ -1086,6 +1087,18 @@ class AnimatedTransform extends AnimatedWithChildren {
|
||||
this._transforms = transforms;
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
super.__makeNative();
|
||||
this._transforms.forEach(transform => {
|
||||
for (var key in transform) {
|
||||
var value = transform[key];
|
||||
if (value instanceof Animated) {
|
||||
value.__makeNative();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
__getValue(): Array<Object> {
|
||||
return this._transforms.map(transform => {
|
||||
var result = {};
|
||||
@ -1138,6 +1151,25 @@ class AnimatedTransform extends AnimatedWithChildren {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
var transConfig = {};
|
||||
|
||||
this._transforms.forEach(transform => {
|
||||
for (var key in transform) {
|
||||
var value = transform[key];
|
||||
if (value instanceof Animated) {
|
||||
transConfig[key] = value.__getNativeTag();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
NativeAnimatedHelper.validateTransform(transConfig);
|
||||
return {
|
||||
type: 'transform',
|
||||
transform: transConfig,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class AnimatedStyle extends AnimatedWithChildren {
|
||||
|
@ -74,16 +74,22 @@ var API = {
|
||||
var PROPS_WHITELIST = {
|
||||
style: {
|
||||
opacity: true,
|
||||
|
||||
transform: true,
|
||||
/* legacy android transform properties */
|
||||
scaleX: true,
|
||||
scaleY: true,
|
||||
rotation: true,
|
||||
translateX: true,
|
||||
translateY: true,
|
||||
},
|
||||
};
|
||||
|
||||
var TRANSFORM_WHITELIST = {
|
||||
translateX: true,
|
||||
translateY: true,
|
||||
scale: true,
|
||||
rotate: true,
|
||||
};
|
||||
|
||||
function validateProps(params: Object): void {
|
||||
for (var key in params) {
|
||||
if (!PROPS_WHITELIST.hasOwnProperty(key)) {
|
||||
@ -92,6 +98,14 @@ function validateProps(params: Object): void {
|
||||
}
|
||||
}
|
||||
|
||||
function validateTransform(config: Object): void {
|
||||
for (var key in config) {
|
||||
if (!TRANSFORM_WHITELIST.hasOwnProperty(key)) {
|
||||
throw new Error(`Property '${key}' is not supported by native animated module`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validateStyles(styles: Object): void {
|
||||
var STYLES_WHITELIST = PROPS_WHITELIST.style || {};
|
||||
for (var key in styles) {
|
||||
@ -129,6 +143,7 @@ module.exports = {
|
||||
API,
|
||||
validateProps,
|
||||
validateStyles,
|
||||
validateTransform,
|
||||
validateInterpolation,
|
||||
generateNewNodeTag,
|
||||
generateNewAnimationId,
|
||||
|
@ -62,7 +62,7 @@ describe('Animated', () => {
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
jasmine.any(Number),
|
||||
jasmine.any(Number),
|
||||
{type: 'frames', frames: jasmine.any(Array), toValue: jasmine.any(Number)},
|
||||
{type: 'frames', frames: jasmine.any(Array), toValue: jasmine.any(Number), delay: jasmine.any(Number)},
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
@ -201,7 +201,7 @@ describe('Animated', () => {
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
jasmine.any(Number),
|
||||
jasmine.any(Number),
|
||||
{type: 'frames', frames: jasmine.any(Array), toValue: jasmine.any(Number)},
|
||||
{type: 'frames', frames: jasmine.any(Array), toValue: jasmine.any(Number), delay: jasmine.any(Number)},
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
@ -341,7 +341,7 @@ describe('Animated', () => {
|
||||
.toBeCalledWith(jasmine.any(Number), { type: 'props', props: { style: jasmine.any(Number) }});
|
||||
});
|
||||
|
||||
it('send stopAnimation command to native', () => {
|
||||
it('sends stopAnimation command to native', () => {
|
||||
var value = new Animated.Value(0);
|
||||
var animation = Animated.timing(value, {toValue: 10, duration: 50, useNativeDriver: true});
|
||||
var nativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
|
||||
@ -350,7 +350,7 @@ describe('Animated', () => {
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
jasmine.any(Number),
|
||||
jasmine.any(Number),
|
||||
{type: 'frames', frames: jasmine.any(Array), toValue: jasmine.any(Number)},
|
||||
{type: 'frames', frames: jasmine.any(Array), toValue: jasmine.any(Number), delay: jasmine.any(Number)},
|
||||
jasmine.any(Function)
|
||||
);
|
||||
var animationId = nativeAnimatedModule.startAnimatingNode.mock.calls[0][0];
|
||||
|
14
Libraries/NativeAnimation/Nodes/RCTAdditionAnimatedNode.h
Normal file
14
Libraries/NativeAnimation/Nodes/RCTAdditionAnimatedNode.h
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
|
||||
@interface RCTAdditionAnimatedNode : RCTValueAnimatedNode
|
||||
|
||||
@end
|
28
Libraries/NativeAnimation/Nodes/RCTAdditionAnimatedNode.m
Normal file
28
Libraries/NativeAnimation/Nodes/RCTAdditionAnimatedNode.m
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTAdditionAnimatedNode.h"
|
||||
|
||||
@implementation RCTAdditionAnimatedNode
|
||||
|
||||
- (void)performUpdate
|
||||
{
|
||||
[super performUpdate];
|
||||
NSArray<NSNumber *> *inputNodes = self.config[@"input"];
|
||||
if (inputNodes.count > 1) {
|
||||
RCTValueAnimatedNode *parent1 = (RCTValueAnimatedNode *)self.parentNodes[inputNodes[0]];
|
||||
RCTValueAnimatedNode *parent2 = (RCTValueAnimatedNode *)self.parentNodes[inputNodes[1]];
|
||||
if ([parent1 isKindOfClass:[RCTValueAnimatedNode class]] &&
|
||||
[parent2 isKindOfClass:[RCTValueAnimatedNode class]]) {
|
||||
self.value = parent1.value + parent2.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
54
Libraries/NativeAnimation/Nodes/RCTAnimatedNode.h
Normal file
54
Libraries/NativeAnimation/Nodes/RCTAnimatedNode.h
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface RCTAnimatedNode : NSObject
|
||||
|
||||
- (instancetype)initWithTag:(NSNumber *)tag
|
||||
config:(NSDictionary<NSString *, id> *)config NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@property (nonatomic, readonly) NSNumber *nodeTag;
|
||||
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id> *config;
|
||||
|
||||
@property (nonatomic, copy, readonly) NSDictionary<NSNumber *, RCTAnimatedNode *> *childNodes;
|
||||
@property (nonatomic, copy, readonly) NSDictionary<NSNumber *, RCTAnimatedNode *> *parentNodes;
|
||||
|
||||
@property (nonatomic, readonly) BOOL needsUpdate;
|
||||
@property (nonatomic, readonly) BOOL hasUpdated;
|
||||
|
||||
/**
|
||||
* Marks a node and its children as needing update.
|
||||
*/
|
||||
- (void)setNeedsUpdate NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
* The node will update its value if necesarry and only after its parents have updated.
|
||||
*/
|
||||
- (void)updateNodeIfNecessary NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
* Where the actual update code lives. Called internally from updateNodeIfNecessary
|
||||
*/
|
||||
- (void)performUpdate NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
* Cleans up after a round of updates.
|
||||
*/
|
||||
- (void)cleanupAnimationUpdate NS_REQUIRES_SUPER;
|
||||
|
||||
- (void)addChild:(RCTAnimatedNode *)child NS_REQUIRES_SUPER;
|
||||
- (void)removeChild:(RCTAnimatedNode *)child NS_REQUIRES_SUPER;
|
||||
|
||||
- (void)onAttachedToNode:(RCTAnimatedNode *)parent NS_REQUIRES_SUPER;
|
||||
- (void)onDetachedFromNode:(RCTAnimatedNode *)parent NS_REQUIRES_SUPER;
|
||||
|
||||
- (void)detachNode NS_REQUIRES_SUPER;
|
||||
|
||||
@end
|
135
Libraries/NativeAnimation/Nodes/RCTAnimatedNode.m
Normal file
135
Libraries/NativeAnimation/Nodes/RCTAnimatedNode.m
Normal file
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTAnimatedNode.h"
|
||||
|
||||
#import "RCTDefines.h"
|
||||
|
||||
@implementation RCTAnimatedNode
|
||||
{
|
||||
NSMutableDictionary<NSNumber *, RCTAnimatedNode *> *_childNodes;
|
||||
NSMutableDictionary<NSNumber *, RCTAnimatedNode *> *_parentNodes;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTag:(NSNumber *)tag
|
||||
config:(NSDictionary<NSString *, id> *)config
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_nodeTag = tag;
|
||||
_config = [config copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
|
||||
- (NSDictionary<NSNumber *, RCTAnimatedNode *> *)childNodes
|
||||
{
|
||||
return _childNodes;
|
||||
}
|
||||
|
||||
- (NSDictionary<NSNumber *, RCTAnimatedNode *> *)parentNodes
|
||||
{
|
||||
return _parentNodes;
|
||||
}
|
||||
|
||||
- (void)addChild:(RCTAnimatedNode *)child
|
||||
{
|
||||
if (!_childNodes) {
|
||||
_childNodes = [NSMutableDictionary new];
|
||||
}
|
||||
if (child) {
|
||||
_childNodes[child.nodeTag] = child;
|
||||
[child onAttachedToNode:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeChild:(RCTAnimatedNode *)child
|
||||
{
|
||||
if (!_childNodes) {
|
||||
return;
|
||||
}
|
||||
if (child) {
|
||||
[_childNodes removeObjectForKey:child.nodeTag];
|
||||
[child onDetachedFromNode:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onAttachedToNode:(RCTAnimatedNode *)parent
|
||||
{
|
||||
if (!_parentNodes) {
|
||||
_parentNodes = [NSMutableDictionary new];
|
||||
}
|
||||
if (parent) {
|
||||
_parentNodes[parent.nodeTag] = parent;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onDetachedFromNode:(RCTAnimatedNode *)parent
|
||||
{
|
||||
if (!_parentNodes) {
|
||||
return;
|
||||
}
|
||||
if (parent) {
|
||||
[_parentNodes removeObjectForKey:parent.nodeTag];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)detachNode
|
||||
{
|
||||
for (RCTAnimatedNode *parent in _parentNodes.allValues) {
|
||||
[parent removeChild:self];
|
||||
}
|
||||
for (RCTAnimatedNode *child in _childNodes.allValues) {
|
||||
[self removeChild:child];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setNeedsUpdate
|
||||
{
|
||||
if (_needsUpdate) {
|
||||
// Has already been marked. Stop branch.
|
||||
return;
|
||||
}
|
||||
_needsUpdate = YES;
|
||||
for (RCTAnimatedNode *child in _childNodes.allValues) {
|
||||
[child setNeedsUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cleanupAnimationUpdate
|
||||
{
|
||||
if (_hasUpdated) {
|
||||
_needsUpdate = NO;
|
||||
_hasUpdated = NO;
|
||||
for (RCTAnimatedNode *child in _childNodes.allValues) {
|
||||
[child cleanupAnimationUpdate];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateNodeIfNecessary
|
||||
{
|
||||
if (_needsUpdate && !_hasUpdated) {
|
||||
for (RCTAnimatedNode *parent in _parentNodes.allValues) {
|
||||
[parent updateNodeIfNecessary];
|
||||
}
|
||||
[self performUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)performUpdate
|
||||
{
|
||||
_hasUpdated = YES;
|
||||
// To be overidden by subclasses
|
||||
// This method is called on a node only if it has been marked for update
|
||||
// during the current update loop
|
||||
}
|
||||
|
||||
@end
|
40
Libraries/NativeAnimation/Nodes/RCTAnimationDriverNode.h
Normal file
40
Libraries/NativeAnimation/Nodes/RCTAnimationDriverNode.h
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
#import "RCTBridgeModule.h"
|
||||
|
||||
@class RCTValueAnimatedNode;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RCTAnimationDriverNode : NSObject
|
||||
|
||||
@property (nonatomic, readonly) NSNumber *animationId;
|
||||
@property (nonatomic, readonly) NSNumber *outputValue;
|
||||
|
||||
@property (nonatomic, readonly) BOOL animationHasBegun;
|
||||
@property (nonatomic, readonly) BOOL animationHasFinished;
|
||||
|
||||
- (instancetype)initWithId:(NSNumber *)animationId
|
||||
delay:(NSTimeInterval)delay
|
||||
toValue:(CGFloat)toValue
|
||||
frames:(NSArray<NSNumber *> *)frames
|
||||
forNode:(RCTValueAnimatedNode *)valueNode
|
||||
callBack:(nullable RCTResponseSenderBlock)callback NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (void)startAnimation;
|
||||
- (void)stopAnimation;
|
||||
- (void)stepAnimation;
|
||||
- (void)removeAnimation;
|
||||
- (void)cleanupAnimationUpdate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
137
Libraries/NativeAnimation/Nodes/RCTAnimationDriverNode.m
Normal file
137
Libraries/NativeAnimation/Nodes/RCTAnimationDriverNode.m
Normal file
@ -0,0 +1,137 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTAnimationDriverNode.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTAnimationUtils.h"
|
||||
#import "RCTDefines.h"
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
|
||||
const double SINGLE_FRAME_INTERVAL = 1.0 / 60.0;
|
||||
|
||||
@implementation RCTAnimationDriverNode
|
||||
{
|
||||
NSArray<NSNumber *> *_frames;
|
||||
CGFloat _toValue;
|
||||
CGFloat _fromValue;
|
||||
NSTimeInterval _delay;
|
||||
NSTimeInterval _animationStartTime;
|
||||
NSTimeInterval _animationCurrentTime;
|
||||
RCTValueAnimatedNode *_valueNode;
|
||||
RCTResponseSenderBlock _callback;
|
||||
}
|
||||
|
||||
- (instancetype)initWithId:(nonnull NSNumber *)animationId
|
||||
delay:(NSTimeInterval)delay
|
||||
toValue:(CGFloat)toValue
|
||||
frames:(nonnull NSArray<NSNumber *> *)frames
|
||||
forNode:(nonnull RCTValueAnimatedNode *)valueNode
|
||||
callBack:(nullable RCTResponseSenderBlock)callback
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_animationId = animationId;
|
||||
_toValue = toValue;
|
||||
_fromValue = valueNode.value;
|
||||
_valueNode = valueNode;
|
||||
_delay = delay;
|
||||
_frames = [frames copy];
|
||||
_outputValue = @0;
|
||||
_callback = [callback copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
|
||||
- (void)startAnimation
|
||||
{
|
||||
_animationStartTime = CACurrentMediaTime();
|
||||
_animationCurrentTime = _animationStartTime;
|
||||
_animationHasBegun = YES;
|
||||
}
|
||||
|
||||
- (void)stopAnimation
|
||||
{
|
||||
_animationHasFinished = YES;
|
||||
}
|
||||
|
||||
- (void)removeAnimation
|
||||
{
|
||||
[self stopAnimation];
|
||||
_valueNode = nil;
|
||||
if (_callback) {
|
||||
_callback(@[(id)kCFNull]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stepAnimation
|
||||
{
|
||||
if (!_animationHasBegun || _animationHasFinished || _frames.count == 0) {
|
||||
// Animation has not begun or animation has already finished.
|
||||
return;
|
||||
}
|
||||
|
||||
NSTimeInterval currentTime = CACurrentMediaTime();
|
||||
NSTimeInterval stepInterval = currentTime - _animationCurrentTime;
|
||||
_animationCurrentTime = currentTime;
|
||||
NSTimeInterval currentDuration = _animationCurrentTime - _animationStartTime;
|
||||
|
||||
if (_delay > 0) {
|
||||
// Decrement delay
|
||||
_delay -= stepInterval;
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine how many frames have passed since last update.
|
||||
// Get index of frames that surround the current interval
|
||||
NSUInteger startIndex = floor(currentDuration / SINGLE_FRAME_INTERVAL);
|
||||
NSUInteger nextIndex = startIndex + 1;
|
||||
|
||||
if (nextIndex >= _frames.count) {
|
||||
// We are at the end of the animation
|
||||
// Update value and flag animation has ended.
|
||||
NSNumber *finalValue = _frames.lastObject;
|
||||
[self updateOutputWithFrameOutput:finalValue.doubleValue];
|
||||
[self stopAnimation];
|
||||
return;
|
||||
}
|
||||
|
||||
// Do a linear remap of the two frames to safegaurd against variable framerates
|
||||
NSNumber *fromFrameValue = _frames[startIndex];
|
||||
NSNumber *toFrameValue = _frames[nextIndex];
|
||||
NSTimeInterval fromInterval = startIndex * SINGLE_FRAME_INTERVAL;
|
||||
NSTimeInterval toInterval = nextIndex * SINGLE_FRAME_INTERVAL;
|
||||
|
||||
// Interpolate between the individual frames to ensure the animations are
|
||||
//smooth and of the proper duration regardless of the framerate.
|
||||
CGFloat frameOutput = RCTInterpolateValue(currentDuration,
|
||||
fromInterval,
|
||||
toInterval,
|
||||
fromFrameValue.doubleValue,
|
||||
toFrameValue.doubleValue);
|
||||
|
||||
[self updateOutputWithFrameOutput:frameOutput];
|
||||
}
|
||||
|
||||
- (void)updateOutputWithFrameOutput:(CGFloat)frameOutput
|
||||
{
|
||||
CGFloat outputValue = RCTInterpolateValue(frameOutput, 0, 1, _fromValue, _toValue);
|
||||
_outputValue = @(outputValue);
|
||||
_valueNode.value = outputValue;
|
||||
[_valueNode setNeedsUpdate];
|
||||
}
|
||||
|
||||
- (void)cleanupAnimationUpdate
|
||||
{
|
||||
[_valueNode cleanupAnimationUpdate];
|
||||
}
|
||||
|
||||
@end
|
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
|
||||
@interface RCTInterpolationAnimatedNode : RCTValueAnimatedNode
|
||||
|
||||
@end
|
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTInterpolationAnimatedNode.h"
|
||||
#import "RCTAnimationUtils.h"
|
||||
|
||||
@implementation RCTInterpolationAnimatedNode
|
||||
{
|
||||
__weak RCTValueAnimatedNode *_parentNode;
|
||||
NSArray<NSNumber *> *_inputRange;
|
||||
NSArray<NSNumber *> *_outputRange;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTag:(NSNumber *)tag
|
||||
config:(NSDictionary<NSString *, id> *)config
|
||||
{
|
||||
if ((self = [super initWithTag:tag config:config])) {
|
||||
_inputRange = [config[@"inputRange"] copy];
|
||||
NSMutableArray *outputRange = [NSMutableArray array];
|
||||
for (id value in config[@"outputRange"]) {
|
||||
if ([value isKindOfClass:[NSNumber class]]) {
|
||||
[outputRange addObject:value];
|
||||
} else if ([value isKindOfClass:[NSString class]]) {
|
||||
NSString *str = (NSString *)value;
|
||||
if ([str hasSuffix:@"deg"]) {
|
||||
double degrees = str.doubleValue;
|
||||
[outputRange addObject:@(RCTDegreesToRadians(degrees))];
|
||||
} else {
|
||||
// Assume radians
|
||||
[outputRange addObject:@(str.doubleValue)];
|
||||
}
|
||||
}
|
||||
}
|
||||
_outputRange = [outputRange copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)onAttachedToNode:(RCTAnimatedNode *)parent
|
||||
{
|
||||
[super onAttachedToNode:parent];
|
||||
if ([parent isKindOfClass:[RCTValueAnimatedNode class]]) {
|
||||
_parentNode = (RCTValueAnimatedNode *)parent;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onDetachedFromNode:(RCTAnimatedNode *)parent
|
||||
{
|
||||
[super onDetachedFromNode:parent];
|
||||
if (_parentNode == parent) {
|
||||
_parentNode = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSUInteger)findIndexOfNearestValue:(CGFloat)value
|
||||
inRange:(NSArray<NSNumber *> *)range
|
||||
{
|
||||
NSUInteger index;
|
||||
NSUInteger rangeCount = range.count;
|
||||
for (index = 1; index < rangeCount - 1; index++) {
|
||||
NSNumber *inputValue = range[index];
|
||||
if (inputValue.doubleValue >= value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index - 1;
|
||||
}
|
||||
|
||||
- (void)performUpdate
|
||||
{
|
||||
[super performUpdate];
|
||||
if (!_parentNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSUInteger rangeIndex = [self findIndexOfNearestValue:_parentNode.value
|
||||
inRange:_inputRange];
|
||||
NSNumber *inputMin = _inputRange[rangeIndex];
|
||||
NSNumber *inputMax = _inputRange[rangeIndex + 1];
|
||||
NSNumber *outputMin = _outputRange[rangeIndex];
|
||||
NSNumber *outputMax = _outputRange[rangeIndex + 1];
|
||||
|
||||
CGFloat outputValue = RCTInterpolateValue(_parentNode.value,
|
||||
inputMin.doubleValue,
|
||||
inputMax.doubleValue,
|
||||
outputMin.doubleValue,
|
||||
outputMax.doubleValue);
|
||||
self.value = outputValue;
|
||||
}
|
||||
|
||||
@end
|
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
|
||||
@interface RCTMultiplicationAnimatedNode : RCTValueAnimatedNode
|
||||
|
||||
@end
|
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTMultiplicationAnimatedNode.h"
|
||||
|
||||
@implementation RCTMultiplicationAnimatedNode
|
||||
|
||||
- (void)performUpdate
|
||||
{
|
||||
[super performUpdate];
|
||||
|
||||
NSArray<NSNumber *> *inputNodes = self.config[@"input"];
|
||||
if (inputNodes.count > 1) {
|
||||
RCTValueAnimatedNode *parent1 = (RCTValueAnimatedNode *)self.parentNodes[inputNodes[0]];
|
||||
RCTValueAnimatedNode *parent2 = (RCTValueAnimatedNode *)self.parentNodes[inputNodes[1]];
|
||||
if ([parent1 isKindOfClass:[RCTValueAnimatedNode class]] &&
|
||||
[parent2 isKindOfClass:[RCTValueAnimatedNode class]]) {
|
||||
self.value = parent1.value * parent2.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
24
Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.h
Normal file
24
Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.h
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTAnimatedNode.h"
|
||||
|
||||
@class RCTNativeAnimatedModule;
|
||||
@class RCTViewPropertyMapper;
|
||||
|
||||
@interface RCTPropsAnimatedNode : RCTAnimatedNode
|
||||
|
||||
@property (nonatomic, readonly) RCTViewPropertyMapper *propertyMapper;
|
||||
|
||||
- (void)connectToView:(NSNumber *)viewTag animatedModule:(RCTNativeAnimatedModule *)animationModule;
|
||||
- (void)disconnectFromView:(NSNumber *)viewTag;
|
||||
|
||||
- (void)performViewUpdatesIfNecessary;
|
||||
|
||||
@end
|
61
Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m
Normal file
61
Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTPropsAnimatedNode.h"
|
||||
#import "RCTAnimationUtils.h"
|
||||
#import "RCTNativeAnimatedModule.h"
|
||||
#import "RCTStyleAnimatedNode.h"
|
||||
#import "RCTViewPropertyMapper.h"
|
||||
|
||||
@implementation RCTPropsAnimatedNode
|
||||
{
|
||||
RCTStyleAnimatedNode *_parentNode;
|
||||
}
|
||||
|
||||
- (void)onAttachedToNode:(RCTAnimatedNode *)parent
|
||||
{
|
||||
[super onAttachedToNode:parent];
|
||||
if ([parent isKindOfClass:[RCTStyleAnimatedNode class]]) {
|
||||
_parentNode = (RCTStyleAnimatedNode *)parent;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onDetachedFromNode:(RCTAnimatedNode *)parent
|
||||
{
|
||||
[super onDetachedFromNode:parent];
|
||||
if (_parentNode == parent) {
|
||||
_parentNode = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)connectToView:(NSNumber *)viewTag animatedModule:(RCTNativeAnimatedModule *)animationModule
|
||||
{
|
||||
_propertyMapper = [[RCTViewPropertyMapper alloc] initWithViewTag:viewTag animationModule:animationModule];
|
||||
}
|
||||
|
||||
- (void)disconnectFromView:(NSNumber *)viewTag
|
||||
{
|
||||
_propertyMapper = nil;
|
||||
}
|
||||
|
||||
- (void)performUpdate
|
||||
{
|
||||
[super performUpdate];
|
||||
[self performViewUpdatesIfNecessary];
|
||||
}
|
||||
|
||||
- (void)performViewUpdatesIfNecessary
|
||||
{
|
||||
NSDictionary *updates = [_parentNode updatedPropsDictionary];
|
||||
if (updates.count) {
|
||||
[_propertyMapper updateViewWithDictionary:updates];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
16
Libraries/NativeAnimation/Nodes/RCTStyleAnimatedNode.h
Normal file
16
Libraries/NativeAnimation/Nodes/RCTStyleAnimatedNode.h
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTAnimatedNode.h"
|
||||
|
||||
@interface RCTStyleAnimatedNode : RCTAnimatedNode
|
||||
|
||||
- (NSDictionary<NSString *, NSNumber *> *)updatedPropsDictionary;
|
||||
|
||||
@end
|
59
Libraries/NativeAnimation/Nodes/RCTStyleAnimatedNode.m
Normal file
59
Libraries/NativeAnimation/Nodes/RCTStyleAnimatedNode.m
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTStyleAnimatedNode.h"
|
||||
#import "RCTAnimationUtils.h"
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
#import "RCTTransformAnimatedNode.h"
|
||||
|
||||
@implementation RCTStyleAnimatedNode
|
||||
{
|
||||
NSMutableDictionary<NSString *, NSNumber *> *_updatedPropsDictionary;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTag:(NSNumber *)tag
|
||||
config:(NSDictionary<NSString *, id> *)config;
|
||||
{
|
||||
if ((self = [super initWithTag:tag config:config])) {
|
||||
_updatedPropsDictionary = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary *)updatedPropsDictionary
|
||||
{
|
||||
return _updatedPropsDictionary;
|
||||
}
|
||||
|
||||
- (void)performUpdate
|
||||
{
|
||||
[super performUpdate];
|
||||
|
||||
NSDictionary<NSString *, NSNumber *> *style = self.config[@"style"];
|
||||
[style enumerateKeysAndObjectsUsingBlock:^(NSString *property, NSNumber *nodeTag, __unused BOOL *stop) {
|
||||
RCTAnimatedNode *node = self.parentNodes[nodeTag];
|
||||
if (node && node.hasUpdated) {
|
||||
if ([node isKindOfClass:[RCTValueAnimatedNode class]]) {
|
||||
RCTValueAnimatedNode *parentNode = (RCTValueAnimatedNode *)node;
|
||||
[self->_updatedPropsDictionary setObject:@(parentNode.value) forKey:property];
|
||||
} else if ([node isKindOfClass:[RCTTransformAnimatedNode class]]) {
|
||||
RCTTransformAnimatedNode *parentNode = (RCTTransformAnimatedNode *)node;
|
||||
[self->_updatedPropsDictionary addEntriesFromDictionary:parentNode.updatedPropsDictionary];
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)cleanupAnimationUpdate
|
||||
{
|
||||
[super cleanupAnimationUpdate];
|
||||
[_updatedPropsDictionary removeAllObjects];
|
||||
}
|
||||
|
||||
@end
|
16
Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.h
Normal file
16
Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.h
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTAnimatedNode.h"
|
||||
|
||||
@interface RCTTransformAnimatedNode : RCTAnimatedNode
|
||||
|
||||
- (NSDictionary<NSString *, NSNumber *> *)updatedPropsDictionary;
|
||||
|
||||
@end
|
52
Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.m
Normal file
52
Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.m
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTTransformAnimatedNode.h"
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
|
||||
@implementation RCTTransformAnimatedNode
|
||||
{
|
||||
NSMutableDictionary<NSString *, NSNumber *> *_updatedPropsDictionary;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTag:(NSNumber *)tag
|
||||
config:(NSDictionary<NSString *, id> *)config;
|
||||
{
|
||||
if ((self = [super initWithTag:tag config:config])) {
|
||||
_updatedPropsDictionary = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary *)updatedPropsDictionary
|
||||
{
|
||||
return _updatedPropsDictionary;
|
||||
}
|
||||
|
||||
- (void)performUpdate
|
||||
{
|
||||
[super performUpdate];
|
||||
|
||||
NSDictionary<NSString *, NSNumber *> *transforms = self.config[@"transform"];
|
||||
[transforms enumerateKeysAndObjectsUsingBlock:^(NSString *property, NSNumber *nodeTag, __unused BOOL *stop) {
|
||||
RCTAnimatedNode *node = self.parentNodes[nodeTag];
|
||||
if (node.hasUpdated && [node isKindOfClass:[RCTValueAnimatedNode class]]) {
|
||||
RCTValueAnimatedNode *parentNode = (RCTValueAnimatedNode *)node;
|
||||
self->_updatedPropsDictionary[property] = @(parentNode.value);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)cleanupAnimationUpdate
|
||||
{
|
||||
[super cleanupAnimationUpdate];
|
||||
[_updatedPropsDictionary removeAllObjects];
|
||||
}
|
||||
|
||||
@end
|
17
Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h
Normal file
17
Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTAnimatedNode.h"
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface RCTValueAnimatedNode : RCTAnimatedNode
|
||||
|
||||
@property (nonatomic, assign) CGFloat value;
|
||||
|
||||
@end
|
14
Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.m
Normal file
14
Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.m
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
|
||||
@implementation RCTValueAnimatedNode
|
||||
|
||||
@end
|
337
Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj
Normal file
337
Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj
Normal file
@ -0,0 +1,337 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
13E501CC1D07A644005F35D8 /* RCTAnimationUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501B81D07A644005F35D8 /* RCTAnimationUtils.m */; };
|
||||
13E501CF1D07A644005F35D8 /* RCTNativeAnimatedModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501BE1D07A644005F35D8 /* RCTNativeAnimatedModule.m */; };
|
||||
13E501D41D07A644005F35D8 /* RCTViewPropertyMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501C81D07A644005F35D8 /* RCTViewPropertyMapper.m */; };
|
||||
13E501E81D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501D71D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m */; };
|
||||
13E501E91D07A6C9005F35D8 /* RCTAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501D91D07A6C9005F35D8 /* RCTAnimatedNode.m */; };
|
||||
13E501EA1D07A6C9005F35D8 /* RCTAnimationDriverNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DB1D07A6C9005F35D8 /* RCTAnimationDriverNode.m */; };
|
||||
13E501EB1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DD1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m */; };
|
||||
13E501EC1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DF1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.m */; };
|
||||
13E501ED1D07A6C9005F35D8 /* RCTPropsAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E11D07A6C9005F35D8 /* RCTPropsAnimatedNode.m */; };
|
||||
13E501EE1D07A6C9005F35D8 /* RCTStyleAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E31D07A6C9005F35D8 /* RCTStyleAnimatedNode.m */; };
|
||||
13E501EF1D07A6C9005F35D8 /* RCTTransformAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E51D07A6C9005F35D8 /* RCTTransformAnimatedNode.m */; };
|
||||
13E501F01D07A6C9005F35D8 /* RCTValueAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E71D07A6C9005F35D8 /* RCTValueAnimatedNode.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
58B511D91A9E6C8500147676 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "include/$(PRODUCT_NAME)";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
134814201AA4EA6300B7C361 /* libRCTAnimation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTAnimation.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13E501B71D07A644005F35D8 /* RCTAnimationUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimationUtils.h; sourceTree = "<group>"; };
|
||||
13E501B81D07A644005F35D8 /* RCTAnimationUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAnimationUtils.m; sourceTree = "<group>"; };
|
||||
13E501BD1D07A644005F35D8 /* RCTNativeAnimatedModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTNativeAnimatedModule.h; sourceTree = "<group>"; };
|
||||
13E501BE1D07A644005F35D8 /* RCTNativeAnimatedModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTNativeAnimatedModule.m; sourceTree = "<group>"; };
|
||||
13E501C71D07A644005F35D8 /* RCTViewPropertyMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTViewPropertyMapper.h; sourceTree = "<group>"; };
|
||||
13E501C81D07A644005F35D8 /* RCTViewPropertyMapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTViewPropertyMapper.m; sourceTree = "<group>"; };
|
||||
13E501D61D07A6C9005F35D8 /* RCTAdditionAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAdditionAnimatedNode.h; sourceTree = "<group>"; };
|
||||
13E501D71D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAdditionAnimatedNode.m; sourceTree = "<group>"; };
|
||||
13E501D81D07A6C9005F35D8 /* RCTAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimatedNode.h; sourceTree = "<group>"; };
|
||||
13E501D91D07A6C9005F35D8 /* RCTAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAnimatedNode.m; sourceTree = "<group>"; };
|
||||
13E501DA1D07A6C9005F35D8 /* RCTAnimationDriverNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimationDriverNode.h; sourceTree = "<group>"; };
|
||||
13E501DB1D07A6C9005F35D8 /* RCTAnimationDriverNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAnimationDriverNode.m; sourceTree = "<group>"; };
|
||||
13E501DC1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTInterpolationAnimatedNode.h; sourceTree = "<group>"; };
|
||||
13E501DD1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTInterpolationAnimatedNode.m; sourceTree = "<group>"; };
|
||||
13E501DE1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMultiplicationAnimatedNode.h; sourceTree = "<group>"; };
|
||||
13E501DF1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMultiplicationAnimatedNode.m; sourceTree = "<group>"; };
|
||||
13E501E01D07A6C9005F35D8 /* RCTPropsAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPropsAnimatedNode.h; sourceTree = "<group>"; };
|
||||
13E501E11D07A6C9005F35D8 /* RCTPropsAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPropsAnimatedNode.m; sourceTree = "<group>"; };
|
||||
13E501E21D07A6C9005F35D8 /* RCTStyleAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStyleAnimatedNode.h; sourceTree = "<group>"; };
|
||||
13E501E31D07A6C9005F35D8 /* RCTStyleAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStyleAnimatedNode.m; sourceTree = "<group>"; };
|
||||
13E501E41D07A6C9005F35D8 /* RCTTransformAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTransformAnimatedNode.h; sourceTree = "<group>"; };
|
||||
13E501E51D07A6C9005F35D8 /* RCTTransformAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTransformAnimatedNode.m; sourceTree = "<group>"; };
|
||||
13E501E61D07A6C9005F35D8 /* RCTValueAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTValueAnimatedNode.h; sourceTree = "<group>"; };
|
||||
13E501E71D07A6C9005F35D8 /* RCTValueAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTValueAnimatedNode.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
58B511D81A9E6C8500147676 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
134814211AA4EA7D00B7C361 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
134814201AA4EA6300B7C361 /* libRCTAnimation.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
13E501D51D07A6C9005F35D8 /* Nodes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13E501D61D07A6C9005F35D8 /* RCTAdditionAnimatedNode.h */,
|
||||
13E501D71D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m */,
|
||||
13E501D81D07A6C9005F35D8 /* RCTAnimatedNode.h */,
|
||||
13E501D91D07A6C9005F35D8 /* RCTAnimatedNode.m */,
|
||||
13E501DA1D07A6C9005F35D8 /* RCTAnimationDriverNode.h */,
|
||||
13E501DB1D07A6C9005F35D8 /* RCTAnimationDriverNode.m */,
|
||||
13E501DC1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.h */,
|
||||
13E501DD1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m */,
|
||||
13E501DE1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.h */,
|
||||
13E501DF1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.m */,
|
||||
13E501E01D07A6C9005F35D8 /* RCTPropsAnimatedNode.h */,
|
||||
13E501E11D07A6C9005F35D8 /* RCTPropsAnimatedNode.m */,
|
||||
13E501E21D07A6C9005F35D8 /* RCTStyleAnimatedNode.h */,
|
||||
13E501E31D07A6C9005F35D8 /* RCTStyleAnimatedNode.m */,
|
||||
13E501E41D07A6C9005F35D8 /* RCTTransformAnimatedNode.h */,
|
||||
13E501E51D07A6C9005F35D8 /* RCTTransformAnimatedNode.m */,
|
||||
13E501E61D07A6C9005F35D8 /* RCTValueAnimatedNode.h */,
|
||||
13E501E71D07A6C9005F35D8 /* RCTValueAnimatedNode.m */,
|
||||
);
|
||||
path = Nodes;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
58B511D21A9E6C8500147676 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13E501B71D07A644005F35D8 /* RCTAnimationUtils.h */,
|
||||
13E501B81D07A644005F35D8 /* RCTAnimationUtils.m */,
|
||||
13E501C71D07A644005F35D8 /* RCTViewPropertyMapper.h */,
|
||||
13E501C81D07A644005F35D8 /* RCTViewPropertyMapper.m */,
|
||||
13E501BD1D07A644005F35D8 /* RCTNativeAnimatedModule.h */,
|
||||
13E501BE1D07A644005F35D8 /* RCTNativeAnimatedModule.m */,
|
||||
13E501D51D07A6C9005F35D8 /* Nodes */,
|
||||
134814211AA4EA7D00B7C361 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
58B511DA1A9E6C8500147676 /* RCTAnimation */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTAnimation" */;
|
||||
buildPhases = (
|
||||
58B511D71A9E6C8500147676 /* Sources */,
|
||||
58B511D81A9E6C8500147676 /* Frameworks */,
|
||||
58B511D91A9E6C8500147676 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = RCTAnimation;
|
||||
productName = RCTDataManager;
|
||||
productReference = 134814201AA4EA6300B7C361 /* libRCTAnimation.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
58B511D31A9E6C8500147676 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0730;
|
||||
ORGANIZATIONNAME = Facebook;
|
||||
TargetAttributes = {
|
||||
58B511DA1A9E6C8500147676 = {
|
||||
CreatedOnToolsVersion = 6.1.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTAnimation" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 58B511D21A9E6C8500147676;
|
||||
productRefGroup = 58B511D21A9E6C8500147676;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
58B511DA1A9E6C8500147676 /* RCTAnimation */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
58B511D71A9E6C8500147676 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
13E501F01D07A6C9005F35D8 /* RCTValueAnimatedNode.m in Sources */,
|
||||
13E501EE1D07A6C9005F35D8 /* RCTStyleAnimatedNode.m in Sources */,
|
||||
13E501CC1D07A644005F35D8 /* RCTAnimationUtils.m in Sources */,
|
||||
13E501CF1D07A644005F35D8 /* RCTNativeAnimatedModule.m in Sources */,
|
||||
13E501EC1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.m in Sources */,
|
||||
13E501ED1D07A6C9005F35D8 /* RCTPropsAnimatedNode.m in Sources */,
|
||||
13E501E91D07A6C9005F35D8 /* RCTAnimatedNode.m in Sources */,
|
||||
13E501EB1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m in Sources */,
|
||||
13E501E81D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m in Sources */,
|
||||
13E501EA1D07A6C9005F35D8 /* RCTAnimationDriverNode.m in Sources */,
|
||||
13E501EF1D07A6C9005F35D8 /* RCTTransformAnimatedNode.m in Sources */,
|
||||
13E501D41D07A644005F35D8 /* RCTViewPropertyMapper.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
58B511ED1A9E6C8500147676 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_SHADOW = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
WARNING_CFLAGS = (
|
||||
"-Werror",
|
||||
"-Wall",
|
||||
);
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
58B511EE1A9E6C8500147676 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_SHADOW = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
WARNING_CFLAGS = (
|
||||
"-Werror",
|
||||
"-Wall",
|
||||
);
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
58B511F01A9E6C8500147676 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../../React/**",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = RCTAnimation;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
58B511F11A9E6C8500147676 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../../React/**",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = RCTAnimation;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTAnimation" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
58B511ED1A9E6C8500147676 /* Debug */,
|
||||
58B511EE1A9E6C8500147676 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTAnimation" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
58B511F01A9E6C8500147676 /* Debug */,
|
||||
58B511F11A9E6C8500147676 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 58B511D31A9E6C8500147676 /* Project object */;
|
||||
}
|
22
Libraries/NativeAnimation/RCTAnimationUtils.h
Normal file
22
Libraries/NativeAnimation/RCTAnimationUtils.h
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
#import "RCTDefines.h"
|
||||
|
||||
RCT_EXTERN CGFloat RCTInterpolateValue(CGFloat value,
|
||||
CGFloat fromMin,
|
||||
CGFloat fromMax,
|
||||
CGFloat toMin,
|
||||
CGFloat toMax);
|
||||
|
||||
RCT_EXTERN CGFloat RCTRadiansToDegrees(CGFloat radians);
|
||||
RCT_EXTERN CGFloat RCTDegreesToRadians(CGFloat degrees);
|
32
Libraries/NativeAnimation/RCTAnimationUtils.m
Normal file
32
Libraries/NativeAnimation/RCTAnimationUtils.m
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTAnimationUtils.h"
|
||||
|
||||
/**
|
||||
* Interpolates value by remapping it linearly fromMin->fromMax to toMin->toMax
|
||||
*/
|
||||
CGFloat RCTInterpolateValue(CGFloat value,
|
||||
CGFloat fromMin,
|
||||
CGFloat fromMax,
|
||||
CGFloat toMin,
|
||||
CGFloat toMax)
|
||||
{
|
||||
return toMin + (value - fromMin) * (toMax - toMin) / (fromMax - fromMin);
|
||||
}
|
||||
|
||||
CGFloat RCTRadiansToDegrees(CGFloat radians)
|
||||
{
|
||||
return radians * 180.0 / M_PI;
|
||||
}
|
||||
|
||||
CGFloat RCTDegreesToRadians(CGFloat degrees)
|
||||
{
|
||||
return degrees / 180.0 * M_PI;
|
||||
}
|
13
Libraries/NativeAnimation/RCTNativeAnimatedModule.h
Normal file
13
Libraries/NativeAnimation/RCTNativeAnimatedModule.h
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
#import "RCTBridgeModule.h"
|
||||
|
||||
@interface RCTNativeAnimatedModule : NSObject <RCTBridgeModule>
|
||||
|
||||
@end
|
247
Libraries/NativeAnimation/RCTNativeAnimatedModule.m
Normal file
247
Libraries/NativeAnimation/RCTNativeAnimatedModule.m
Normal file
@ -0,0 +1,247 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
#import "RCTNativeAnimatedModule.h"
|
||||
|
||||
#import "RCTAdditionAnimatedNode.h"
|
||||
#import "RCTAnimationDriverNode.h"
|
||||
#import "RCTAnimationUtils.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTInterpolationAnimatedNode.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTMultiplicationAnimatedNode.h"
|
||||
#import "RCTPropsAnimatedNode.h"
|
||||
#import "RCTStyleAnimatedNode.h"
|
||||
#import "RCTTransformAnimatedNode.h"
|
||||
#import "RCTValueAnimatedNode.h"
|
||||
|
||||
@implementation RCTNativeAnimatedModule
|
||||
{
|
||||
NSMutableDictionary<NSNumber *, RCTAnimatedNode *> *_animationNodes;
|
||||
NSMutableDictionary<NSNumber *, RCTAnimationDriverNode *> *_animationDrivers;
|
||||
NSMutableSet<RCTAnimationDriverNode *> *_activeAnimations;
|
||||
NSMutableSet<RCTAnimationDriverNode *> *_finishedAnimations;
|
||||
NSMutableSet<RCTValueAnimatedNode *> *_updatedValueNodes;
|
||||
NSMutableSet<RCTPropsAnimatedNode *> *_propAnimationNodes;
|
||||
CADisplayLink *_displayLink;
|
||||
}
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
_bridge = bridge;
|
||||
_animationNodes = [NSMutableDictionary new];
|
||||
_animationDrivers = [NSMutableDictionary new];
|
||||
_activeAnimations = [NSMutableSet new];
|
||||
_finishedAnimations = [NSMutableSet new];
|
||||
_updatedValueNodes = [NSMutableSet new];
|
||||
_propAnimationNodes = [NSMutableSet new];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(createAnimatedNode:(nonnull NSNumber *)tag
|
||||
config:(NSDictionary<NSString *, id> *)config)
|
||||
{
|
||||
static NSDictionary *map;
|
||||
static dispatch_once_t mapToken;
|
||||
dispatch_once(&mapToken, ^{
|
||||
map = @{@"style" : [RCTStyleAnimatedNode class],
|
||||
@"value" : [RCTValueAnimatedNode class],
|
||||
@"props" : [RCTPropsAnimatedNode class],
|
||||
@"interpolation" : [RCTInterpolationAnimatedNode class],
|
||||
@"addition" : [RCTAdditionAnimatedNode class],
|
||||
@"multiplication" : [RCTMultiplicationAnimatedNode class],
|
||||
@"transform" : [RCTTransformAnimatedNode class]};
|
||||
});
|
||||
|
||||
NSString *nodeType = [RCTConvert NSString:config[@"type"]];
|
||||
|
||||
Class nodeClass = map[nodeType];
|
||||
if (!nodeClass) {
|
||||
RCTLogError(@"Animated node type %@ not supported natively", nodeType);
|
||||
return;
|
||||
}
|
||||
|
||||
RCTAnimatedNode *node = [[nodeClass alloc] initWithTag:tag config:config];
|
||||
_animationNodes[tag] = node;
|
||||
|
||||
if ([node isKindOfClass:[RCTPropsAnimatedNode class]]) {
|
||||
[_propAnimationNodes addObject:(RCTPropsAnimatedNode *)node];
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(connectAnimatedNodes:(nonnull NSNumber *)parentTag
|
||||
childTag:(nonnull NSNumber *)childTag)
|
||||
{
|
||||
RCTAssertParam(parentTag);
|
||||
RCTAssertParam(childTag);
|
||||
|
||||
RCTAnimatedNode *parentNode = _animationNodes[parentTag];
|
||||
RCTAnimatedNode *childNode = _animationNodes[childTag];
|
||||
|
||||
RCTAssertParam(parentNode);
|
||||
RCTAssertParam(childNode);
|
||||
|
||||
[parentNode addChild:childNode];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(disconnectAnimatedNodes:(nonnull NSNumber *)parentTag
|
||||
childTag:(nonnull NSNumber *)childTag)
|
||||
{
|
||||
RCTAssertParam(parentTag);
|
||||
RCTAssertParam(childTag);
|
||||
|
||||
RCTAnimatedNode *parentNode = _animationNodes[parentTag];
|
||||
RCTAnimatedNode *childNode = _animationNodes[childTag];
|
||||
|
||||
RCTAssertParam(parentNode);
|
||||
RCTAssertParam(childNode);
|
||||
|
||||
[parentNode removeChild:childNode];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(startAnimatingNode:(nonnull NSNumber *)animationId
|
||||
nodeTag:(nonnull NSNumber *)nodeTag
|
||||
config:(NSDictionary<NSString *, id> *)config
|
||||
endCallback:(RCTResponseSenderBlock)callBack)
|
||||
{
|
||||
if (RCT_DEBUG && ![config[@"type"] isEqual:@"frames"]) {
|
||||
RCTLogError(@"Unsupported animation type: %@", config[@"type"]);
|
||||
return;
|
||||
}
|
||||
|
||||
NSTimeInterval delay = [RCTConvert double:config[@"delay"]];
|
||||
NSNumber *toValue = [RCTConvert NSNumber:config[@"toValue"]] ?: @1;
|
||||
NSArray<NSNumber *> *frames = [RCTConvert NSNumberArray:config[@"frames"]];
|
||||
|
||||
RCTValueAnimatedNode *valueNode = (RCTValueAnimatedNode *)_animationNodes[nodeTag];
|
||||
|
||||
RCTAnimationDriverNode *animationDriver =
|
||||
[[RCTAnimationDriverNode alloc] initWithId:animationId
|
||||
delay:delay
|
||||
toValue:toValue.doubleValue
|
||||
frames:frames
|
||||
forNode:valueNode
|
||||
callBack:callBack];
|
||||
[_activeAnimations addObject:animationDriver];
|
||||
_animationDrivers[animationId] = animationDriver;
|
||||
[animationDriver startAnimation];
|
||||
[self startAnimation];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(stopAnimation:(nonnull NSNumber *)animationId)
|
||||
{
|
||||
RCTAnimationDriverNode *driver = _animationDrivers[animationId];
|
||||
if (driver) {
|
||||
[driver removeAnimation];
|
||||
[_animationDrivers removeObjectForKey:animationId];
|
||||
[_activeAnimations removeObject:driver];
|
||||
[_finishedAnimations removeObject:driver];
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(setAnimatedNodeValue:(nonnull NSNumber *)nodeTag
|
||||
value:(nonnull NSNumber *)value)
|
||||
{
|
||||
RCTAnimatedNode *node = _animationNodes[nodeTag];
|
||||
if (![node isKindOfClass:[RCTValueAnimatedNode class]]) {
|
||||
RCTLogError(@"Not a value node.");
|
||||
return;
|
||||
}
|
||||
RCTValueAnimatedNode *valueNode = (RCTValueAnimatedNode *)node;
|
||||
valueNode.value = value.floatValue;
|
||||
[valueNode setNeedsUpdate];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(connectAnimatedNodeToView:(nonnull NSNumber *)nodeTag
|
||||
viewTag:(nonnull NSNumber *)viewTag)
|
||||
{
|
||||
RCTAnimatedNode *node = _animationNodes[nodeTag];
|
||||
if (viewTag && [node isKindOfClass:[RCTPropsAnimatedNode class]]) {
|
||||
[(RCTPropsAnimatedNode *)node connectToView:viewTag animatedModule:self];
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(disconnectAnimatedNodeFromView:(nonnull NSNumber *)nodeTag
|
||||
viewTag:(nonnull NSNumber *)viewTag)
|
||||
{
|
||||
RCTAnimatedNode *node = _animationNodes[nodeTag];
|
||||
if (viewTag && node && [node isKindOfClass:[RCTPropsAnimatedNode class]]) {
|
||||
[(RCTPropsAnimatedNode *)node disconnectFromView:viewTag];
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(dropAnimatedNode:(nonnull NSNumber *)tag)
|
||||
{
|
||||
RCTAnimatedNode *node = _animationNodes[tag];
|
||||
if (node) {
|
||||
[node detachNode];
|
||||
[_animationNodes removeObjectForKey:tag];
|
||||
if ([node isKindOfClass:[RCTValueAnimatedNode class]]) {
|
||||
[_updatedValueNodes removeObject:(RCTValueAnimatedNode *)node];
|
||||
} else if ([node isKindOfClass:[RCTPropsAnimatedNode class]]) {
|
||||
[_propAnimationNodes removeObject:(RCTPropsAnimatedNode *)node];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -- Animation Loop
|
||||
|
||||
- (void)startAnimation
|
||||
{
|
||||
if (!_displayLink && _activeAnimations.count > 0) {
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateAnimations)];
|
||||
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateAnimations
|
||||
{
|
||||
// Step Current active animations
|
||||
// This also recursively marks children nodes as needing update
|
||||
for (RCTAnimationDriverNode *animationDriver in _activeAnimations) {
|
||||
[animationDriver stepAnimation];
|
||||
}
|
||||
|
||||
// Perform node updates for marked nodes.
|
||||
// At this point all nodes that are in need of an update are properly marked as such.
|
||||
for (RCTPropsAnimatedNode *propsNode in _propAnimationNodes) {
|
||||
[propsNode updateNodeIfNecessary];
|
||||
}
|
||||
|
||||
// Cleanup nodes and prepare for next cycle. Remove updated nodes from bucket.
|
||||
for (RCTAnimationDriverNode *driverNode in _activeAnimations) {
|
||||
[driverNode cleanupAnimationUpdate];
|
||||
}
|
||||
for (RCTValueAnimatedNode *valueNode in _updatedValueNodes) {
|
||||
[valueNode cleanupAnimationUpdate];
|
||||
}
|
||||
[_updatedValueNodes removeAllObjects];
|
||||
|
||||
for (RCTAnimationDriverNode *driverNode in _activeAnimations) {
|
||||
if (driverNode.animationHasFinished) {
|
||||
[driverNode removeAnimation];
|
||||
[_finishedAnimations addObject:driverNode];
|
||||
}
|
||||
}
|
||||
for (RCTAnimationDriverNode *driverNode in _finishedAnimations) {
|
||||
[_activeAnimations removeObject:driverNode];
|
||||
[_animationDrivers removeObjectForKey:driverNode.animationId];
|
||||
}
|
||||
[_finishedAnimations removeAllObjects];
|
||||
|
||||
if (_activeAnimations.count == 0) {
|
||||
[_displayLink invalidate];
|
||||
_displayLink = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
22
Libraries/NativeAnimation/RCTViewPropertyMapper.h
Normal file
22
Libraries/NativeAnimation/RCTViewPropertyMapper.h
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RCTNativeAnimatedModule;
|
||||
|
||||
@interface RCTViewPropertyMapper : NSObject
|
||||
|
||||
@property (nonatomic, readonly) NSNumber *viewTag;
|
||||
|
||||
- (instancetype)initWithViewTag:(NSNumber *)viewTag
|
||||
animationModule:(RCTNativeAnimatedModule *)animationModule NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (void)updateViewWithDictionary:(NSDictionary<NSString *, NSNumber *> *)updates;
|
||||
|
||||
@end
|
94
Libraries/NativeAnimation/RCTViewPropertyMapper.m
Normal file
94
Libraries/NativeAnimation/RCTViewPropertyMapper.m
Normal file
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTViewPropertyMapper.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTUIManager.h"
|
||||
#import "RCTNativeAnimatedModule.h"
|
||||
|
||||
@implementation RCTViewPropertyMapper
|
||||
{
|
||||
CGFloat _translateX;
|
||||
CGFloat _translateY;
|
||||
CGFloat _scaleX;
|
||||
CGFloat _scaleY;
|
||||
CGFloat _rotation;
|
||||
RCTNativeAnimatedModule *_animationModule;
|
||||
}
|
||||
|
||||
- (instancetype)initWithViewTag:(NSNumber *)viewTag
|
||||
animationModule:(RCTNativeAnimatedModule *)animationModule
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_animationModule = animationModule;
|
||||
_viewTag = viewTag;
|
||||
_translateX = 0;
|
||||
_translateY = 0;
|
||||
_scaleX = 1;
|
||||
_scaleY = 1;
|
||||
_rotation = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
|
||||
- (void)updateViewWithDictionary:(NSDictionary<NSString *, NSNumber *> *)updates
|
||||
{
|
||||
if (updates.count) {
|
||||
UIView *view = [_animationModule.bridge.uiManager viewForReactTag:_viewTag];
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSNumber *opacity = updates[@"opacity"];
|
||||
if (opacity) {
|
||||
view.alpha = opacity.doubleValue;
|
||||
}
|
||||
|
||||
NSNumber *scale = updates[@"scale"];
|
||||
if (scale) {
|
||||
_scaleX = scale.doubleValue;
|
||||
_scaleY = scale.doubleValue;
|
||||
}
|
||||
NSNumber *scaleX = updates[@"scaleX"];
|
||||
if (scaleX) {
|
||||
_scaleX = scaleX.doubleValue;
|
||||
}
|
||||
NSNumber *scaleY = updates[@"scaleY"];
|
||||
if (scaleY) {
|
||||
_scaleY = scaleY.doubleValue;
|
||||
}
|
||||
NSNumber *translateX = updates[@"translateX"];
|
||||
if (translateX) {
|
||||
_translateX = translateX.doubleValue;
|
||||
}
|
||||
NSNumber *translateY = updates[@"translateY"];
|
||||
if (translateY) {
|
||||
_translateY = translateY.doubleValue;
|
||||
}
|
||||
NSNumber *rotation = updates[@"rotate"];
|
||||
if (rotation) {
|
||||
_rotation = rotation.doubleValue;
|
||||
}
|
||||
|
||||
if (translateX || translateY || scale || scaleX || scaleY || rotation) {
|
||||
CATransform3D xform = CATransform3DMakeScale(_scaleX, _scaleY, 0);
|
||||
xform = CATransform3DTranslate(xform, _translateX, _translateY, 0);
|
||||
xform = CATransform3DRotate(xform, _rotation, 0, 0, 1);
|
||||
view.layer.allowsEdgeAntialiasing = YES;
|
||||
view.layer.transform = xform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
Loading…
x
Reference in New Issue
Block a user