在上次随笔(系列三)中,我试着用RN实现了一个Demo,感觉很不错,当时遇到的问题这篇文章里基本都解决了,比如导航动画问题,这篇文章里主要介绍RN的动画,学会动画以后,各种小创意都可以实现了^^
下面是我自己做的效果:
1、列表项滑动显示操作按钮
2、列表行滑出
3、K线页面
4、转场动画
一、React Native动画
RN的动画实现类似Jquery和CSS3的动画实现,设定某一属性的输入和输出值,后台实现相关的动画计算,简化了动画的开发,下面是一段代码,可以直观感受下
class Playground extends React.Component { constructor(props: any) { super(props); this.state = { bounceValue: new Animated.Value(0), //设定初始值 }; } render(): ReactElement { return ( <Animated.Image // Base: Image, Text, View,这三个标签可以实现动画,必须是Animate.开头,普通的Image不能实现动画。 source={{uri: 'http://i.imgur.com/XMKOH81.jpg'}} style={{ flex: 1, transform: [ // `transform` 类似CSS3 {scale: this.state.bounceValue}, // 设置 `bounceValue` 给 `scale`,注意,这里要使用上面再state里创建的对象,不能重新实例一个对象赋值。 ] }} /> ); } //UI渲染结束后执行该方法 componentDidMount() { this.state.bounceValue.setValue(1.5); // 设定初始大小,使用的依旧是在state中创建的对象。 Animated.spring( .state.bounceValue, // Animate `bounceValue`初始输入值 { toValue: 0.8, // Animate to smaller size,动画目标值 friction: 1, // Bouncier spring,这个值类似设置弹簧的弹性。 } ).start(); // Start the animation,开始动画,start的参数是一个动画结束的callback。 } }
RN动画的主要类库是Animated库,Animated库包括Value和ValueXY两个类型,Value是单值的动画,比较简单,就是某个属性值的改变,ValueXY是向量的动画,就是两个值的改变,参数X,Y是元素的坐标,根据XY的变化计算运动方向。目前支持动画的元素View, Text, and Image,用户可以自己创建动画元素,通过Animated.createAnimatedComponent来创建。
目前主要有三种动画实现:spring, decay, timing,
组合动画:
如果需要同时执行多个动画,或者按顺序执行动画,就需要将动画组合执行,RN提供了parallel, sequence, stagger, delay, 这个四个方法组合动画,这些方法的参数都是一个动画的数组,使用起来很简单,parallel是并行执行, sequence是顺序执行, stagger是每个动画延迟一段时间执行, delay是延时,下面是代码示例:
Animated.sequence([ // spring to start and twirl after decay finishes Animated.decay(position, { // coast to a stop velocity: {x: gestureState.vx, y: gestureState.vy}, // velocity from gesture release deceleration: 0.997, }), Animated.parallel([ // after decay, in parallel: Animated.spring(position, { toValue: {x: 0, y: 0} // return to start }), Animated.timing(twirl, { // and twirl toValue: 360, }), ]), ]).start(); // start the sequence group
关于RN动画更多内容参考:
二、动画demo
我做了一个动画的demo,这里只是改变了元素的left属性,大家体验下:
'use strict'; var React = require('react-native'); var Easing = require('Easing'); var { TouchableWithoutFeedback, StyleSheet, View, Image, Text, Animated, Dimensions, InteractionManager } = React; var SCREEN_WIDTH = Dimensions.get('window').width; var Component = React.createClass({ getInitialState: function() { return { first:new Animated.Value(0), second:new Animated.Value(0), three:new Animated.Value(0) }; }, reset:function (argument) { this.state.first.setValue(0); this.state.second.setValue(0); this.state.three.setValue(0); }, getAnimations:function (argument) { return[ Animated.spring( .state.first, // Animate `bounceValue` { toValue: SCREEN_WIDTH-50, // Animate to smaller size friction: 7, tension:40 // Bouncier spring } ), Animated.decay( .state.second, // Animate `bounceValue` { //toValue: SCREEN_WIDTH-50, // Animate to smaller size velocity: 1, deceleration:0.997 // Bouncier spring } ), Animated.timing( .state.three, // Animate `bounceValue` { toValue: SCREEN_WIDTH-50, // Animate to smaller size easing: Easing.inOut(Easing.ease), delay:0 // Bouncier spring } ) ]; }, onStagger:function (argument) { this.reset(); Animated.stagger(150,this.getAnimations()).start(); }, onParallel:function (argument) { this.reset(); Animated.parallel(this.getAnimations()).start(); }, onSequence:function (argument) { this.reset(); Animated.sequence(this.getAnimations()).start(); }, onAll:function (argument) { var me=this; this.reset(); Animated.sequence([ Animated.stagger(50,me.getAnimations()), Animated.sequence([ Animated.spring( .state.first, // Animate `bounceValue` { toValue: 0, // Animate to smaller size friction: 7, tension:40 // Bouncier spring } ), Animated.decay( .state.second, // Animate `bounceValue` { //toValue: SCREEN_WIDTH-50, // Animate to smaller size velocity: -1, deceleration:0.997 // Bouncier spring } ), Animated.timing( .state.three, // Animate `bounceValue` { toValue: 0, // Animate to smaller size easing: Easing.bezier(.13,.93,.79,.07), delay:0 // Bouncier spring } ) ]), Animated.parallel(me.getAnimations()) ]).start(); }, render: function() { return ( <View style={styles.container}> <View style={{flex:1}}> <Animated.View style={[styles.view,{top:50,left:this.state.first}]}><Text>spring</Text></Animated.View> <Animated.View style={[styles.view,{top:150,left:this.state.second}]}><Text>decay</Text></Animated.View> <Animated.View style={[styles.view,{top:250,left:this.state.three}]}><Text>timing</Text></Animated.View> </View> <View style={{flexDirection:'row',height:80,justifyContent :'center',alignItems: 'center'}}> <TouchableWithoutFeedback onPress={this.onStagger}> <View style={styles.btn}><Text>stagger</Text></View> </TouchableWithoutFeedback> <TouchableWithoutFeedback onPress={this.onParallel}> <View style={styles.btn}><Text>parallel</Text></View> </TouchableWithoutFeedback> <TouchableWithoutFeedback onPress={this.onSequence}> <View style={styles.btn}><Text>sequence</Text></View> </TouchableWithoutFeedback> <TouchableWithoutFeedback onPress={this.onAll}> <View style={styles.btn}><Text>组合</Text></View> </TouchableWithoutFeedback> </View> </View> ); } }); var styles = StyleSheet.create({ container:{ flex:1 }, view:{ position:'absolute', backgroundColor:'red', width:50, height:50, justifyContent :'center', alignItems: 'center', }, btn:{ width:100, height:50, backgroundColor:'red', justifyContent :'center', alignItems: 'center', margin:5 } }); module.exports = Component;
RN动画示例
三、性能优化