mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-01 09:23:16 +08: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 Differential Revision: D3401811 Pulled By: nicklockwood fbshipit-source-id: c8d750b75e4410923e17eaeb6dcaf079a09942e2
This commit is contained in:
committed by
Facebook Github Bot 4
parent
7357ccc370
commit
5ecdb252c3
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'),
|
||||
|
||||
Reference in New Issue
Block a user