React Native 动画(LayoutAnimation)
平时进行 Native 开发的时候,为了更好的用户体验,我们会做一些动画效果,而在 React Native 中也提供了相应的动画API。
React Native 主要的动画分为两大类:
- LayoutAnimation 用来实现布局切换的动画。
- Animated 更加精确的交互式的动画。
这篇文章主要说的是 LayoutAnimation 的用法,之后会写重点讲解 Animated 的文章。
LayoutAnimation
LayoutAnimation 是在布局发生变化时触发动画的接口,这意味着你需要通过修改布局(比如修改了组件的style、插入新组件)来触发动画。一个常用的调用此API的办法是调用 LayoutAnimation.configureNext,然后调用setState。
配置相关:
static configureNext(config: Config, onAnimationDidEnd?: Function)
计划下一次布局要发生的动画。
@param config 表示动画相应的属性:
duration 动画持续时间,单位是毫秒。
create 配置创建新视图时的动画。
update 配置被更新的视图的动画。
@param onAnimationDidEnd 当动画结束的时候被调用。只在iOS设备上支持。
@param onError 当动画产生错误的时候被调用。只在iOS设备上支持。
static create(duration: number, type, creationProp)
用来创建 configureNext 所需的 config 参数的辅助函数。
其中 config 参数格式参考:
LayoutAnimation.configureNext({
duration: 700, //动画持续时间
create: { //若是新布局的动画类型
type: 'linear', //线性模式,LayoutAnimation.Types.linear 写法亦可
property: 'opacity' //动画属性,除了opacity 还有一个 scaleXY 可以配置,LayoutAnimation.Properties.opacity 写法亦可
},
update: { //若是布局更新的动画类型
type: 'spring', //弹跳模式
springDamping: 0.4 //弹跳阻尼系数
}
});
create、update 的属性:
duration:动画持续时间(单位:毫秒),会覆盖 config 中设置的 duration。
delay:延迟指定时间(单位:毫秒)。
springDamping:弹跳动画阻尼系数(配合 spring 使用)。
initialVelocity:初始速度。
type:类型定义在LayoutAnimation.Types中:
spring:弹跳
linear:线性
easeInEaseOut:缓入缓出
easeIn:缓入
easeOut:缓出
property:类型定义在LayoutAnimation.Properties中:
opacity:透明度
scaleXY:缩放
示例:
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
Dimensions,
LayoutAnimation,
} from 'react-native';
var screenW = Dimensions.get('window').width;
var screenH = Dimensions.get('window').height;
export default class extends Component {
constructor(props) {
super(props)
this.state = {
width: 100,
height: 150,
left:20,
top:20,
}
}
_clickStartAnimation() {
LayoutAnimation.configureNext({
duration: 1000, //持续时间
create: {
type: LayoutAnimation.Types.spring,
property: 'opacity',
},
update: {
type: 'spring',
springDamping: 0.4,
}
});
this.setState({
width: this.state.width + 40,
height: this.state.height + 60,
left: this.state.left + 20,
top: this.state.top + 50,
});
}
render(){
return (
<View style={styles.mainStyle}>
<Image style={{width:this.state.width,height:this.state.height,position:'absolute',left:this.state.left, top:this.state.top}}
source={{uri:'beauty.jpg'}}>
</Image>
<TouchableOpacity style={{width:200,height:50,backgroundColor:'yellow',marginTop:40}} onPress={this._clickStartAnimation.bind(this)}>
<Text style={{width:200,height:50,textAlign:'center',lineHeight:50}}>点击开始动画</Text>
</TouchableOpacity>
</View>
);
}
}
效果图:
效果图.gif
实现拆解:
在 update 中的 type 为 spring,每次点击按钮,图片都会改变宽高和位置,会有一个移动和缩放的动画效果。
人民币装入红包动画:
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
Dimensions,
LayoutAnimation,
} from 'react-native';
var anima = {
duration: 1000, //持续时间
create: {
type: LayoutAnimation.Types.spring,
property: LayoutAnimation.Properties.scaleXY,
},
update: {
type: 'easeOut',
}
};
export default class extends Component {
constructor(props) {
super(props)
this.state = {
width: 200,
height: 100,
left:100,
top:20,
}
}
_clickStartAnimation() {
LayoutAnimation.configureNext(anima,()=>{
this.setState({
top: 20,
});
});
this.setState({
top: this.state.top + 200,
});
}
_setTimer(){
// 先开始一次动画
this._clickStartAnimation();
// 创建定时器
this.timer = setInterval(this._clickStartAnimation.bind(this),1200);
}
render(){
return (
<View style={styles.mainStyle}>
<Image style={{width:this.state.width,height:this.state.height,position:'absolute',left:this.state.left, top:this.state.top}}
source={{uri:'100.jpg'}}>
</Image>
<View style={{
width:240,
height:120,
position:'absolute',
left:80,
top:200,
backgroundColor:'red',
}}>
<Text style={{color:'#FFD700',fontSize:90,lineHeight:104,width:240, textAlign:'center'}}>红包</Text>
</View>
<TouchableOpacity style={{width:200,height:50,backgroundColor:'yellow',marginTop:40}} onPress={this._setTimer.bind(this)}>
<Text style={{width:200,height:50,textAlign:'center',lineHeight:50}}>点击开始动画</Text>
</TouchableOpacity>
</View>
);
}
}
效果图:
红包效果图.gif实现拆解:
首先创建一个 config 变量,1秒的持续时间,type 为 easeOut,然后在点击按钮之后,先执行一次动画,并同时开启定时器,1.2秒执行一次动画,在每次的动画执行完成之后,让100元回到原位,然后再次执行动画。
魔法现金动画:
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
Dimensions,
LayoutAnimation,
} from 'react-native';
var anima = {
duration: 1000, //持续时间
create: {
type: LayoutAnimation.Types.linear,
property: LayoutAnimation.Properties.scaleXY,
},
update: {
type: 'linear',
}
};
export default class extends Component {
constructor(props) {
super(props)
this.state = {
width: 250,
height: 125,
show:false,
}
}
_clickStartAnimation() {
LayoutAnimation.configureNext(anima,()=>{});
this.setState({
show: true,
});
}
render(){
var secondMoney = this.state.show ? (
<Image style={{width:this.state.width,height:this.state.height}}
source={{uri:'100.jpg'}}>
</Image>
) : null;
return (
<View style={styles.mainStyle}>
<Image style={{width:this.state.width,height:this.state.height}}
source={{uri:'100.jpg'}}>
</Image>
{secondMoney}
<TouchableOpacity style={{width:200,height:50,backgroundColor:'yellow',marginTop:40}} onPress={this._clickStartAnimation.bind(this)}>
<Text style={{width:200,height:50,textAlign:'center',lineHeight:50}}>魔法现金</Text>
</TouchableOpacity>
</View>
);
}
}
效果图:
魔法现金效果图.gif实现拆解:
首先创建一个 config 变量,1秒的持续时间,type 为 linear,property 为
scaleXY,然后在点击按钮之后,修改 state.show 为 true,然后根据这个属性就会加载出一个新的100元图片,因为是创建,不是更新,所以新的100元图片是执行的 create 内的动画效果,原来的100元图片和按钮则是执行的 update 效果。
LayoutAnimation.create
如果觉得上面的代码太繁杂,还可以通过 LayoutAnimation.create 这个函数更简单的创建一个config,也可以实现上面的动画效果。
create函数接受三个参数:
- duration:动画持续时间。
- type:create 和 update 时的动画类型,定义在 LayoutAnimation.Types。
- creationProp:create 时的动画属性,定义 LayoutAnimation.Properties。
用法:
...
_clickStartAnimation() {
LayoutAnimation.configureNext(LayoutAnimation.create(1000,
LayoutAnimation.Types.linear,
LayoutAnimation.Properties.scaleXY));
this.setState({
show: true,
});
}
...
效果图和上面一样,参考上面即可。
LayoutAnimation.Presets
系统也为我们提供了3个默认的动画,定义在LayoutAnimation.Presets中:
- easeInEaseOut:缓入缓出
- linear:线性
- spring:弹性
可以使用这种方式创建一些简单的动画效果。
用法:
...
_clickStartAnimation() {
LayoutAnimation.configureNext(LayoutAnimation.Presets.linear);
this.setState({
show: true,
});
}
...
这个效果和上面类似,区别在于这个默认 Properties 是 opacity,创建过程是透明度的变化。
效果图:
Presets效果图.gif
LayoutAnimation 使用总结:
- LayoutAnimation 在 React Native 中可以很好的实现动画效果,完成可以和原生体验相媲美,非常值得大家一试。
- 效果非常的流畅,而且动画的过程很柔和,丝毫没有生硬的感觉。
- 可以灵活的配置动画参数,基本能满足单个动画的需求。
- 在实现红包效果的时候,需要在动画完成之后执行一些操作,
configureNext 第二个参数可以监听动画结束,从而完成这个需求,但是,这个参数只在 iOS 平台有效,ㄟ( ▔, ▔ )ㄏ。 - 红包动画效果是在动画结束之后执行了一些操作,而如果动画的效果更为复杂,比如同时执行动画,再顺序执行,就会变的非常复杂。
Demo在这里,不麻烦的话 star 一下哈,谢谢!