在React Native中,我们可以通过两种方式实现一个动画效果:
关于LayoutAnimation,我之前写过一篇学习博客(React Native LayoutAnimation动画)。此主要用于在页面布局改变的时候添加一些动画效果,但如果想要实现一些更精细,复杂的动画,LayoutAnimation就会比较困难,所以React Native还为我们提供了Animated组件,用来实现一些复杂的动画效果。
一、单个动画
Animated为我们提供了三种类型的动画:spring,timing,decay。
1、Spring 弹跳效果动画
Spring支持 friction与tension 或者 bounciness与speed 两种组合模式,这两种模式不能并存。 其中friction与tension模型来源于origami,一款F家自制的动画原型设计工具,而bounciness与speed则是传统的弹簧模型参数。
2、timing 带有时间的渐变动画
3、decay 带有加速度值的动画,类似于正弦值
4、另外,现在RN只为我们提供Animated.View,Animated.Image,Animated.Text三种动画组件,但是可以通过Animated.createAnimatedComponent(component)创建动画组件。
具体实现步骤如下:
1、引入Animated组件
import {
StyleSheet,
Animated,//要实现Animated 动画,首先要引入Animated组件
Easing,
View,
Image,
Text,
}from 'react-native';
2、 在构造方法中初始化一个Animated对象
// 构造
constructor(props) {
super(props);
// 初始状态
this.state = {
anim: new Animated.Value(0),//初始化一个动画对象
};
}
3、添加动画组件,并将要改变的动画组件样式属性值设为动画对象
render() {
return (
<View style={styles.container}>
<Animated.Image source={require('../../res/girl.jpg')}
style={[styles.image,{
opacity:this.state.anim,//将动画对象赋值给需要改变的样式属性
}]}/>
View>
)
}
4、执行动画
componentDidMount() {
//timing动画
Animated.timing(//使用timin过度动画
this.state.anim,//要改变的动画对象
{
toValue: 1,//动画结束值
duration: 3000,//动画运行时间
easing: Easing.linear,//动画过渡曲线函数
}
).start();//动画开始执行
随着动画的执行,样式属性的值会一直变化,即实现动画效果。
二、插值函数
我们可以只初始化一个动画对象,然后给多个样式属性赋值,通过interpolate()方法,我们可以将一个区间映射到另一个区间。
render() {
return (
container}>
'../../res/girl.jpg')}
style={[styles.image,{
opacity:this.state.anim,//组件的opacity样式属性
transform:[//组件的transform样式属性
{scale:this.state.anim.interpolate({//组件的scale样式属性,将[0,1]区间映射到[1,2]区间
inputRange:[0,1],//输入区间
outputRange:[1,2]//输出区间
})},
{rotate:this.state.anim.interpolate({//组件的rotate样式属性,将[0,1]区间映射到['0deg','360deg]区间
inputRange:[0,1],//输入区间
outputRange:['0deg','360deg'],//输出区间
})},
]
}]}
/>
)
}
其它代码不变,则随着动画的执行,图片的opacity,scale,rotate都会更改,产生一个淡入,放大,旋转同时进行的动画效果:
三、组合动画
RN为我们提供了三种组合动画方法:
代码实现如下:
/**
* Created by gyg on 2017/5/19.
* Animated学习demo
*/
'use strict'
import React, {Component} from 'react';
import {
StyleSheet,
Animated,
Easing,
View,
Image,
Text,
Dimensions,
}from 'react-native';
var deviceWidth=Dimensions.get('window').width;
export default class AnimatedDemo extends Component {
// 构造
constructor(props) {
super(props);
// 初始状态
this.state = {
data: ['工行大公司都会', '好噶或更多更好的嘎', '规划i哈哈打开建行', '黑啊好的是根据卡号开个会看到个', '嘎机会更多机会关机定时关机'],
initAnims:[],//存放初始化的动画对象
anims: [],//存放动画函数
};
for(let i=0;i<this.state.data.length;i++){//遍历数据
this.state.initAnims.push(new Animated.Value(-250));//每条数据对应一个动画对象
this.state.anims.push(Animated.timing(this.state.initAnims[i],{//每条数据对应一个动画函数
duration:3500,
toValue:deviceWidth+250,
easing:Easing.linear,
}));
}
}
componentDidMount() {
Animated.stagger(1000,this.state.anims).start();//每隔1000ms开始执行动画数组中的一个动画
}
render() {
const views=this.state.data.map((text,i)=>{//每条数据映射一个动画组件
return(
this.state.initAnims[i],//设置translateX为动画值,这样动画执行的时候,translateX的值也会随之改变
},
{
translateY:Math.floor(Math.random()*10),//产生0-9的一个随机数
},
]}]}
>
{text}
)
});
return (
{views}
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
justifyContent: 'center',
},
textview:{
width:200,
paddingTop:10,
paddingBottom:10,
paddingLeft:20,
paddingRight:20,
backgroundColor:'rgba(0,0,0,0.5)',
borderRadius:10,
justifyContent:'center',
alignItems:'center',
fontSize:16,
color:'white',
},
});