React Native動畫之Animated仿網易雲音樂啟動動畫
動畫對於一款APP的重要性,我想不用多說,想必不是搞開發的也明白,雖說APP的簡潔實用性很重要,但UE也是同等重要的。
下面分析下網易雲音樂的啟動動畫,一張開啟圖片縮放的同時首頁也進行縮放,不過首頁初始化的scale可能是1.5,總是初始化放大,然後縮放至正常狀態,造成一種視覺衝擊的效果,如果無法感受到的話,還是下載一枚用用。其實這種效果如果用原生開發的話,很簡單,Activity之間跳轉的動畫配置下就完事了,這裡簡單講下如何用React Native來實現跨平臺的效果。
Animated是一個動畫庫,用來創造流暢、強大、並且易於構建和維護的動畫。
最簡單的工作流程就是建立一個
用到的方法:
static timing(value: AnimatedValue | AnimatedValueXY, config: TimingAnimationConfig)
推動一個值按照一個過渡曲線而隨時間變化。Easing模組定義了一大堆曲線,你也可以使用你自己的函式。
addListener(callback: ValueXYListenerCallback)
監測動畫的變化,因為它並沒有提供像原生那麼全的方法:如:onAnimationStart,onAnimationEnd等,因此只能不停的進行檢測。
這裡我們建立個splash元件,一般會在其constructor中進行宣告:
然後在componentDidMount中進行啟動:constructor(props){ super(props); //初始化兩個變數,一個用於操作scale,一個用於操作opacity. this.state={ bounceAnimValue:new Animated.Value(1), opacityAnimValue:new Animated.Value(1), }; }
componentDidMount(){
//第一引數是要修改的變數,第二個是配置config,
Animated.timing(
this.state.bounceAnimValue,
{
toValue: 0.8,
duration: 400,
delay:1000,
easing:Easing.linear,
}
).start();
Animated.timing(
this.state.opacityAnimValue,
{
toValue:0,
duration:400,
delay:1000,
easing:Easing.linear,
}
).start();
this.state.bounceAnimValue.addListener(value=>{
if(value.value=='0.8'){
this.props.onAnimEnd();
}
});
}
程式碼相對還算清晰,easing其實類似於安卓中的Interpolator,可以設定多種形式。
這裡用到addListener進行檢測動畫結束後進行回撥給主頁面。
下面我們來看下如何render:
render(){
return(
<View style={[styles.container,this.props.style]}>
<Animated.Image
source={require('./images/splash.jpg')}
style={{
flex: 1,
width: Util.size.width,
height:null,
opacity: this.state.opacityAnimValue,
transform: [
{scale: this.state.bounceAnimValue},
],
}} />
</View>
);
}
注意:只有宣告為可動畫化的元件才能被關聯動畫。View、Text,還有Image都是可動畫化的。
如果你想讓自定義元件可動畫化,可以用createAnimatedComponent。如:
const AnimatedIcon = Animated.createAnimatedComponent(Icon);
。。。
<AnimatedIcon
size={60}
style={[styles.twitter,{transform:[{scale:this.state.transformAnim}]}]}
name="social-twitter"/>
以上是針對splash啟動頁的操作,同理我們也要對首頁進行相應的動畫,下面主要看下首頁的render函式:
render(){
let defaultName='app';
let defaultComponent=App;
return (
<View style={styles.container}>
<View style={styles.main}>
<Animated.View
style={{
flex:1,
transform: [
{scale: this.state.bounceAnimValue},
]
}}>
<Navigator
initialRoute={{name:defaultName,component:defaultComponent}}
configureScene={()=>Navigator.SceneConfigs.PushFromRight}
renderScene={(route, navigator) => {
let Component = route.component;
return <Component {...route.params} navigator={navigator} />
}} />
</Animated.View>
</View>
{this.state.splashed?
null:
<Splash
style={{height:Util.size.height,position:'absolute'}}
onAnimEnd={this.onAnimEnd}
/>
}
</View>
);
}
style:
var styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor:'#fff'
},
main:{
height:Platform.OS==='android'?Util.size.height-24:Util.size.height,
width:Util.size.width,
position:'absolute',
}
});
看上去不難理解,將我們的Animated.View包裹住首頁內容實現其整體動畫效果。但這裡有個需要注意的地方,由於splash元件和首頁的Navigator元件是屬於同一個頁面內部,其實也就是splash元件在navigator元件的上方,但React Native並沒有原生那麼多種佈局(直接用RelativeLayout包裹兩個控制元件就成了),但在React Native中,想要實現其效果,需要用到absolute佈局並且設定寬和高。
如圖:紅色:是最外層的元件,藍色和黑色要想處於前後效果,需要都設定:
{position:'absolute',width:300,height:500}固定大小,選用absolute佈局這樣就實現了這種形式。
至此我們就寫完了,下面我們看下效果吧
RN開發群:527459711.歡迎大夥加入.