前言
動(dòng)畫是移動(dòng)應(yīng)用中的一個(gè)相當(dāng)重要的組成部分,一個(gè)用戶體驗(yàn)良好的應(yīng)用通常都具有流暢、有意義的動(dòng)畫。類似原生平臺(tái),React Native也為我們提供了豐富的動(dòng)畫API:requestAnimationFrame、LayoutAnimation、Animated。
requestAnimationFrame:幀動(dòng)畫,是最容易實(shí)現(xiàn)的一種動(dòng)畫,通過不斷改變組件的state值,從而在視覺上產(chǎn)生一種動(dòng)畫的效果,類似于gif動(dòng)畫的方式。
LayoutAnimation:布局動(dòng)畫,當(dāng)布局發(fā)生改變時(shí)的動(dòng)畫模塊,允許在全局范圍內(nèi)創(chuàng)建和更新動(dòng)畫,這些動(dòng)畫會(huì)在下一次渲染或布局周期運(yùn)行,實(shí)現(xiàn)單個(gè)動(dòng)畫非常簡(jiǎn)潔,體驗(yàn)和性能良好。
Animated:用于創(chuàng)建更精細(xì)的交互控制的動(dòng)畫,可進(jìn)行多個(gè)動(dòng)畫的組合動(dòng)畫,具備極高的性能,是功能最強(qiáng)大的動(dòng)畫API。
本節(jié)我們先介紹requestAnimationFrame。
requestAnimationFrame幀動(dòng)畫的實(shí)現(xiàn)
requestAnimationFrame實(shí)現(xiàn)幀動(dòng)畫的原理非常粗暴簡(jiǎn)潔,即通過修改state值來不斷得改變視圖上的樣式,從而在視覺上產(chǎn)生一種動(dòng)畫的效果。
import React, { Component } from'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity,
Platform,
} from'react-native';
exportdefaultclassFrameAnimationDemo extends Component {
constructor(props){
super(props);
this.state = {
width:200,
height:20,
};
}
_onPress() {
//每按一次增加近30寬高
varcount =0;
while(++count<30){
requestAnimationFrame(()=>{
this.setState({
width:this.state.width +1,
height:this.state.height +1
});
})
}
}
render() {
return(
<Viewstyle={styles.container}>
<Viewstyle={[styles.content,{width:this.state.width,height:this.state.height}]}>
<Textstyle={[{textAlign:'center'}]}>Hello World!</Text>
</View>
<TouchableOpacitystyle={styles.content}onPress={this._onPress.bind(this)}>
<Viewstyle={styles.button}>
<Textstyle={styles.buttonText}>Press me!</Text>
</View>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
marginTop:25,
flex: 1,
},
content: {
backgroundColor: 'rgba(200, 230, 255, 0.8)',
marginBottom:10,
justifyContent:"center",
alignSelf:"center",
},
button: Platform.select({
ios: {},
android: {
elevation: 4,
// Material design blue from https://material.google.com/style/color.html#color-color-palette
backgroundColor: '#2196F3',
borderRadius: 2,
width:100,
height:30,
},
justifyContent:"center",
alignSelf:"center",
}),
buttonText: {
alignSelf:"center",
}
});
從效果上看動(dòng)畫有種一頓一頓的感覺。這是由于通過修改state值,導(dǎo)致頻繁地銷毀、重繪視圖,內(nèi)存開銷大,從而使得動(dòng)畫卡頓明顯。另外對(duì)于幀動(dòng)畫而言,如果幀數(shù)較少,動(dòng)畫的效果會(huì)比較生硬,幀數(shù)過多又會(huì)引發(fā)性能問題。
優(yōu)化
如果幀動(dòng)畫的方式更符合當(dāng)前對(duì)動(dòng)畫的控制方式,我們可以對(duì)上述方法做一點(diǎn)優(yōu)化,在requestAnimationFrame中采用setNativeProps直接修改組件的屬性并觸發(fā)局部刷新,不會(huì)導(dǎo)致重繪組件,因此在性能上優(yōu)于直接修改state的方法。
修改_onPress方法,將對(duì)this.setState的直接修改改為對(duì)”Hello World”按鈕的屬性修改this.refs.view1.setNativeProps。
_onPress() {
varcount =0;
while(++count<30){
requestAnimationFrame(()=>{
this.refs.view1.setNativeProps({
style: {
width:this.state.width++,
height:this.state.height++
}
});
});
}
}
this.refs.view1指向的是”Hello World”文字的父視圖。
<View ref="view1"style={[styles.content, {width:this.state.width, height:this.state.height}]}>
<Textstyle={[{textAlign:'center'}]}>Hello World!</Text>
</View>
通過對(duì)比可以看出流暢順滑多了。
每個(gè)動(dòng)畫API都有其適應(yīng)和不適應(yīng)的場(chǎng)景,如果要實(shí)現(xiàn)“彈性動(dòng)畫”,“緩入緩出”等效果,使用requestAnimationFrame還是比較難的,需要輔助各種函數(shù)。下一節(jié)將介紹另一種動(dòng)畫API——LayoutAnimation。