天天看點

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

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

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

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

步驟拆解

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 則是傳統的彈簧模型參數。

栗子不夠複雜?

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

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

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

強大的插值 interpolate

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

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

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

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

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

流程控制

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

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

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

3、delay 生成一個延遲時間(預設值為0,機關為毫秒)

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

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

需要注意的點

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

使用原生驅動

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

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

ShouldComponentUpdate

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

SetNativeProps (局部重新整理)

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

LayoutAnimation

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

繼續閱讀