前端知識 | React Native Animated動畫淺談



       在移動開發中,動畫能有效的提高用戶體驗。在 React Native 中,也有相應的 API 供我們做動畫。這裏着重說一下 Animated 動畫庫,它可以讓我們非常簡便的去實現各式各樣的動畫和交互方式,而且具備很高的性能。Animated 目前只封裝了四個可以動畫化的組件:View、Text、Image、ScrollView,不過你也可以用 Animated.createAnimatedComponent() 來封裝你自己的組件。

 

話不多說,我們來舉個栗子:



步驟拆解


1、創建 Animated.Value,設置初始值,比如一個 View 組件的透明度,最開始設置 fadeAnim:Animated.Value(0) 來表示動畫開始的時候,是透明的。


2、把創建的這個 Animated.Value 綁定到 Style 的動畫屬性,例:<View style={{opacity:this.state.fadeAnim}}></View>


3、使用 Animated.timing (還有其他的)來創建自動的動畫,或者使用 Animated.event 來根據手勢,觸摸,Scroll 的動態更新動畫的狀態。


4、調用 Animated.timing.start() 開始動畫, start 接受一個回調函數作爲參數,將會在執行了動畫之後執行回調函數。


動畫模式


如果只是 timing ,肯定是無法滿足我們複雜的交互效果的需求的,所以 RN 還給我們提供了另外兩種動畫模式。


1、spring 彈簧效果

      friction 摩擦係數,默認爲40

      tension 張力系數,默認爲7

      bounciness

      speed


2、decay 衰變效果

      velocity 出速率

      deceleration 衰減係數,默認爲0.997


spring 支持 friction 與 tension 或者 bounciness 與 speed 兩種組合模式,這兩種模式不能並存。其中 friction 與 tension 模型來源於 Origami ,一款F家自制的動畫原型設計工具,而 bounciness 與 speed 則是傳統的彈簧模型參數。


栗子不夠複雜?


看來一個簡單的淡入是無法滿足大家的好奇心的,我們整個大點的。

 


在上面的例子裏面,我們實現的是三個動畫效果同時進行,因爲我們給文字區域加上了字體增大的動畫效果,相應地,也要修改 Text 爲 Animated.Text


強大的插值 interpolate


相信大家都已經注意到了,我們上面用到了 interpolate 這個函數,也就是插值函數。這個函數很強大,當我們動畫的值與要改變的屬性值不是同一單位的時候,就可以使用 interpolate 來幫我們進行一個單位的映射轉換,比如



當 rotation 這個動畫狀態的值爲0時,那麼輸出的Z軸上的旋轉角度會自動映射成0deg。當 rotation 這個動畫狀態的值爲0.5時,那麼輸出的Z軸上的旋轉角度會自動映射成180deg。以此類推。 InputRange 並不侷限於 [0,1] 區間,這個主要取決於你定義的動畫的初始值,和想要變化以後的值,並且其間還可以存在多段映射。插值的好處在於我們可以聲明一個動畫變量來控制多個並行動畫,簡單易控制。



Interpolate 支持多段區間映射, [0,1] 區間和 [1,2] 區間之間沒有什麼必然聯繫,當 rotation 趨近於1時,動畫旋轉趨近於360deg,當 rotation 趨近於2時,動畫也可以旋轉回來趨近於200deg,唯一要注意的就是 inputRange 的每一個值都必須有一個 outputRange 裏面的值與其對應。


流程控制


在剛纔的栗子中,我們使用了 parallel 來實現多個動畫的並行渲染,其他用於流程控制的 API 還有:


1、sequence 接受一系列動畫數組爲參數,並依次執行


2、stagger 接受一系列動畫數組和一個延遲時間,按照序列,每隔一個延遲時間後執行下一個動畫(其實就是插入了 delay 的 parallel )


3、delay 生成一個延遲時間(默認值爲0,單位爲毫秒)



第二個栗子稍微修改一下,就可以根據業務邏輯去控制自己的動畫流程,在上面的栗子裏面,我們讓動畫首先出現,出現了之後,再同時進行字體變大和旋轉兩個動畫,雖然他們持續的時間和到達的值不一樣,但是他們是在 opacity 變爲1以後同時開始的。


需要注意的點


可以看到我們上面的動畫都是以毫秒級的頻率來執行的,也就相當於我們會以毫秒級的頻率去調用 setState,而每次調用 setState 都會重新調用 render 方法遍歷子元素進行渲染,就算有 dom diff 幫我們算,他也會累的(負擔不起這麼大的計算量和 UI 渲染量)。這裏淺談幾個優化方案,具體收益就只有大家在實際項目中自己體會了。


使用原生驅動


這算是官方給出的一個比較簡單的解決方案了,在動畫中啓用原生驅動非常簡單。只需在開始動畫之前,在動畫配置中加入一行 useNativeDriver:true 。


 


ShouldComponentUpdate


大家都知道,ShouldComponentUpdate 是性能優化利器,只需要在子組件的 ShouldComponentUpdate 返回 false,就可以省去很多多餘渲染花費。這樣做也有一個弊端,畢竟我們的子元素並不是一成不變的,這樣粗暴的直接返回 false 的話,會讓子元素變成一灘死水,所以使用的時候請權衡利弊。

 

SetNativeProps (局部刷新)


可能這都不算是動畫的的優化方案,但是卻可以直接改動組件並觸發局部的刷新。使用這個方法修改 View、Text 等 RN 自帶的組件,就不會觸發組件的 componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate 等組件生命週期中的方法。

 

LayoutAnimation


這也是官方給的一個比較簡單的動畫解決方案,它允許我們在全局範圍內創建和更新動畫,這些動畫會在下一次渲染或佈局週期運行。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章