React Native Animated動畫
在React Native中,我們可以通過兩種方式實現一個動畫效果:
- LayoutAnimation
- Animated
關於LayoutAnimation,我之前寫過一篇學習部落格(React Native LayoutAnimation動畫)。此主要用於在頁面佈局改變的時候新增一些動畫效果,但如果想要實現一些更精細,複雜的動畫,LayoutAnimation就會比較困難,所以React Native還為我們提供了Animated元件,用來實現一些複雜的動畫效果。
一、單個動畫
Animated為我們提供了三種類型的動畫:spring,timing,decay。
1、Spring 彈跳效果動畫
- friction 摩擦係數,預設40
- tension 張力系數,預設7
或 - bounciness
- speed
Spring支援 friction與tension 或者 bounciness與speed 兩種組合模式,這兩種模式不能並存。 其中friction與tension模型來源於origami,一款F家自制的動畫原型設計工具,而bounciness與speed則是傳統的彈簧模型引數。
2、timing 帶有時間的漸變動畫
- duration 動畫執行時間
- easing 動畫曲線函式,可以從Easing模組中獲取更多預定義的函式
- delay: 動畫執行延遲時間(單位:毫秒).預設為0ms
3、decay 帶有加速度值的動畫,類似於正弦值
- velocity:初始速度,必須要填寫
- deceleration:速度減小的比例,加速度。預設為0.997
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 (
<View style={styles.container}>
<Animted.Image source={require('../../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'],//輸出區間
})},
]
}]}
/>
</View>
)
}
其它程式碼不變,則隨著動畫的執行,圖片的opacity,scale,rotate都會更改,產生一個淡入,放大,旋轉同時進行的動畫效果:
三、組合動畫
RN為我們提供了三種組合動畫方法:
- sequence 順序執行
- parallel 同時執行
- stagger 每隔一段時間開始執行行一個動畫
例如一個彈出字幕的效果:
程式碼實現如下:
/**
* 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(
<Animated.Text key={i}
style={[styles.textview,{
transform:[{
translateX:this.state.initAnims[i],//設定translateX為動畫值,這樣動畫執行的時候,translateX的值也會隨之改變
},
{
translateY:Math.floor(Math.random()*10),//產生0-9的一個隨機數
},
]}]}
>
{text}
</Animated.Text>
)
});
return (
<View style={styles.container}>
{views}
</View>
)
}
}
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',
},
});