react-native的Animated动画基本详解
程序员文章站
2024-01-14 17:14:28
...
一.介绍
动画类型:
spring:基础的单次弹跳物理模型
timing:从时间范围映射到渐变的值
decay:以一个初始速度开始并且逐渐减慢停止
创建动画的参数:
value:AnimatedValue | AnimatedValueXY(X轴或Y轴 | X轴和Y轴)
config:SpringAnimationConfig | TimingAnimationConfig | DecayAnimationConfig(动画的参数配置)
组件类型:
Animated.Text
Animated.Image
Animated.View:可以用来包裹任意视图
Animated.createAnimatedComponent():其它组件(较少用,用Animated.View包裹可以达到同样的效果)
import React, {Component} from 'react';
import {
StyleSheet,
View,
Animated,
Image,
Easing
} from 'react-native';
import {Button} from "react-native-elements";
/**
* @mark 文件内变量
*/
//文件内变量结束
export default class AnimatedDeomo extends React.Component {
/***
* default props value
* @mark propTypes 默认属性值
*/
static defaultProps = {}
/***
* props types for helper text
* @mark propTypes 属性类型
*/
static propTypes = {}
/**
* @mark state
*/
state = {
fadeOutOpacity: new Animated.Value(0),
trans: new Animated.ValueXY({
x: 0,
y: 0
}),
rotation: new Animated.Value(0),
scale: new Animated.Value(1),
left: new Animated.Value(0),
}
/**
* @mark constructor
*/
constructor(props) {
super(props);
}
/**
* @mark 组件声明周期区域
*/
/**
* @mark 第一次加载 只运行一次
*/
componentDidMount() {
}
//声明周期代码结束
/**
* @mark 自定义代码区
*/
/**
* @mark 淡入淡出
*/
OpacityHandle(){
this.startOpacity();
}
startOpacity() {
Animated.timing(this.state.fadeOutOpacity, {
toValue: 1,
duration: 2000,
easing: Easing.linear,// 线性的渐变函数
}).start();
}
/**
* @mark 位移
*/
TransHandle(){
this.startTrans();
}
startTrans() {
Animated.timing(this.state.trans, {
toValue: {
x: 100,
y: 100
},
duration: 2000,
}).start();
}
/**
* @mark 旋转并且持续进行动画
*/
RotationHandle(){
this.startRotation();
}
startRotation(){
this.state.rotation.setValue(0);
Animated.timing(this.state.rotation, {
toValue: 1, //属性目标值
duration: 2000 //动画执行时间
}).start(() => this.RotationHandle()); //执行动画
}
/**
* @mark 缩放+spring摩擦力
*/
ScaleHandle(){
this.startScale();
}
startScale(){
Animated.spring(this.state.scale, {
toValue: 2, //属性目标值
duration: 500,
friction: 5, //摩擦力 (越小 振幅越大)
tension: 1000, //拉力
}).start(); //执行动画
/*Animated.timing(this.state.scale, {
toValue: 2,
duration: 500,
}).start();*/
}
/**
* @mark 滚动
*/
LeftHandle(){
this.startLeft();
}
startLeft(){
Animated.timing(this.state.left, {
toValue: 1,
duration: 3000,
}).start();
}
//自定义代码区结束
/**
* @mark render
*/
render() {
return <View style={styles.AnimatedDeomo}>
<Animated.View // 可选的基本组件类型: Image, Text, View(可以包裹任意子View)
style = {{alignItems: 'center',justifyContent: 'center',width:Theme.size.width,height:Theme.size.height/2,
opacity: this.state.fadeOutOpacity,
//可以修改成Left ,Right,top,进行位移转换
bottom:this.state.left.interpolate({
inputRange:[0,1],
outputRange:[0, Theme.size.width/2]
}),
transform:[
{
rotateX: this.state.rotation.interpolate({
inputRange:[0,1],
outputRange:['0deg','360deg']
})
},
{scale: this.state.scale}
]}}>
<Image resizeMode="cover" style={{width:40,height:40,}} source = {require("../../imgs/logo.png")}
/>
</Animated.View >
<Button
fontSize={Theme.fontSize.max}
buttonStyle={styles.loginBtn}
onPress={this.OpacityHandle.bind(this)}
title='淡入淡出'
/>
<Button
fontSize={Theme.fontSize.max}
buttonStyle={styles.loginBtn}
onPress={this.TransHandle.bind(this)}
title='位移'
/>
<Button
fontSize={Theme.fontSize.max}
buttonStyle={styles.loginBtn}
onPress={this.RotationHandle.bind(this)}
title='旋转'
/>
<Button
fontSize={Theme.fontSize.max}
buttonStyle={styles.loginBtn}
onPress={this.ScaleHandle.bind(this)}
title='缩放'
/>
<Button
fontSize={Theme.fontSize.max}
buttonStyle={styles.loginBtn}
onPress={this.LeftHandle.bind(this)}
title='滚动'
/>
</View>
}
}
//@mark style
const styles = StyleSheet.create({
AnimatedDeomo: {
flex:1
},
loginBtn:{
marginTop:Theme.padding.less,
backgroundColor:Theme.color.orange,
borderRadius:Theme.radius.small
}
});
通过上文的讲解,相信读者已经对如何用Animated创建动画有了最基本的认识。而有些时候,我们需要根据Scroll或者手势来手动的控制动画的过程。这就是我接下来要讲的。
手动控制动画的核心是Animated.event,
这里的Aniamted.event的输入是一个数组,用来做数据绑定
比如,
ScrollView中
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: this.state.xOffset}}}]//把contentOffset.x绑定给this.state.xOffset
)}
export default class ScrollAnimated extends React.Component {
/***
* default props value
* @mark propTypes 默认属性值
*/
static defaultProps = {}
/***
* props types for helper text
* @mark propTypes 属性类型
*/
static propTypes = {}
/**
* @mark state
*/
state = {
xOffset: new Animated.Value(0)
}
/**
* @mark constructor
*/
constructor(props) {
super(props);
}
/**
* @mark 组件声明周期区域
*/
/**
* @mark 第一次加载 只运行一次
*/
componentDidMount() {
}
//声明周期代码结束
/**
* @mark 自定义代码区
*/
//自定义代码区结束
/**
* @mark render
*/
render() {
return <View style={styles.ScrollAnimated}>
<ScrollView
style={{height: Theme.size.height, width: Theme.size.width}}//设置大小
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {y: this.state.xOffset}}}]//把contentOffset.x绑定给this.state.xOffset
)}
scrollEventThrottle={100}//onScroll回调间隔
>
<Image source={require('../../imgs/1.png')} style={{height: Theme.size.height, width: Theme.size.width}}
resizeMode="cover"/>
<Image source={require('../../imgs/2.png')} style={{height: Theme.size.height, width: Theme.size.width}}
resizeMode="cover"/>
<Image source={require('../../imgs/3.png')} style={{height: Theme.size.height, width: Theme.size.width}}
resizeMode="cover"/>
</ScrollView>
<Animated.View // 可选的基本组件类型: Image, Text, View(可以包裹任意子View)
style = {[ styles.titleView,{ opacity:this.state.xOffset.interpolate({//映射到0.0,1.0之间
inputRange: [0,Theme.size.height],
outputRange: [0.0, 1.0]
}),
}]}>
<Text style={{color:Theme.color.white,fontSize:15,textAlign:'center'}}>标题</Text>
</Animated.View >
</View>
}
}
//@mark style
const styles = StyleSheet.create({
ScrollAnimated: {
},
titleView:{
alignItems: 'center',
justifyContent: 'center',
width:Theme.size.width,
height:40,
backgroundColor:Theme.color.orange,
position: "absolute",
top: 0,
left: 0
}
});