React-Native 動畫優化


前言

動畫對於客戶端來說是非常重要的一部分,直接影響到應用的用戶體驗。前端對於動畫優化通常使用CSS3樣式來實現動畫,以利用GPU加速特性。而React-Native由於渲染模式的不同,無法使用CSS樣式的方式優化。

React-Native的實現

React-Native在動畫方面有兩個主要方式,一個是Animated,一個是LayoutAnimation。

Animated

Animated動畫庫的原理是由JavaScript來進行動畫的計算,然后在每幀設置對應組件的style來實現動畫過程(requestAnimationFrame)。
這個動畫庫的特點是非常靈活,因為所有的控制都是通過JavaScript實現的,動畫補幀都是在JavaScript端完成,可以實現各種復雜動畫效果,包括跟手動畫等。

但是成也JavaScript敗也JavaScript,JavaScript是單線程的,動畫的特點是要保證流暢就要保證每秒60的幀率,也就是說如果在16ms內處理不完,勢必要掉幀。而在實際業務中,播放動畫的同時一般都會執行一些任務處理邏輯。比如數據拉取、數據計算,典型情況通常會伴有Loading動畫,切換頁面過場時伴隨新頁面數據加載等。在復雜場景下,由於業務邏輯的加入,動畫處理的幀率就很難保證,用我們QA的話說就是卡的像個Web。。。

優點:

  • 可實現復雜動畫
  • 非常靈活
  • 可以兼容Web

缺點:

  • 性能問題,掉幀、卡頓

LayoutAnimation

React-Native自帶還有一種動畫的實現方式,就是LayoutAnimation。這種方案是直接在Native實現一些動畫效果,然后由JavaScript進行設置調用,由於整個動畫過程交由Native處理,使得性能得以保證。不過LayoutAnimation的實現思路有點問題,他只是預置了幾個動畫效果,並且只能配置在create/update/delete的時候,需要自定義的動畫、跟手動畫等都沒法實現。

優點:

  • 性能良好

缺點:

  • 動畫效果簡單,可適用范圍較窄

嘗試解決

給他特權

針對Animated的優化思路就是解決動畫播放時JavaScript任務量的問題,保證動畫循環達到60幀。一個典型的解決方案就是暫時停止所有同步任務的處理,等到動畫執行完成之后再同步或異步的執行任務處理。比如在切頁轉場前暫停耗時操作(延遲Redux的dispatch過程等),轉場動畫結束后再進行同步或異步處理,把大的同步任務用setTimeout等方式拆成多個異步過程處理。

這種方案可以一定程度上解決動畫卡頓的問題,但是有幾個缺點:

  • 任務總是要執行的,延遲處理會導致整個處理過程變長,響應用戶操作速度變慢,影響用戶體驗。
  • 治標不治本,復雜動畫該卡還得卡。。。

優點:

  • 改動較少,成本低,萬一以后facebook改進了呢?比如在獨立線程進行動畫渲染計算?(需要解決數據同步問題,WebWorker也是個坑)
  • 可以實現跟手動畫,控制好JavaScript的任務量,效果還可以

所以此方案適用 動畫相對簡單、后續任務不復雜 的場景

原生優化

要從根本上解決問題,就需要讓動畫過程脫離JavaScript。所以就要開發原生組件來實現動畫過程,這樣可以充分利用機器性能,可以使用GPU進行動畫渲染。還需要考慮靈活性,如果只能實現固定的效果那么使用場景就大打折扣。

然而,我們並不需要從頭設計,OC、Android、WPF,都有優秀的動畫API,我們還等什么?抄吧。

(So,歡迎使用 react-native-animation 支持iOS、Android,目前驗證可行、能用、不完善、待重構,歡迎PR~)

舉個小栗子:

<Animation.AnimationView
    data={[{
        type: 'Alpha',
        from: 0,
        to: 1,
        duration: 500,
    }]} autoplay={true}>
        other views...
</Animation.AnimationView>

*Now support: 'Translate' | 'Rotate' | 'Scale' | 'Alpha'

Props:

export interface PropsDefine {
    data: AnimationModel[]
    style?: React.ViewStyle
    autoplay?: boolean
    autoclear?: boolean
    onStart?: (view: AnimationView) => void
    onEnd?: (view: AnimationView) => void
}

數據模型:

export interface AnimationModel {
    name?: string
    type: 'Translate' | 'Rotate' | 'Scale' | 'Alpha'
    from?: number
    to?: number
    from2?: number
    to2?: number
    duration: number
    startOffset?: number
    interpolator?: 'Linear'
    interpolatorData?: number
    repeat?: number
}

效果演示:
iOS微粉App(android版兼容開發中),業務邏輯全React-Native實現。贊踩動畫、彈幕動畫、切頁動畫、回復/評論彈層動畫已應用優化。

雖然這種方案可以解決可預測的動畫得卡頓問題,缺點也很明顯:

  • 動畫的過程是預設好的,所以無法實現跟手動畫

優點:

  • 動畫過程交由Native處理,性能Max,JavaScript任務處理不影響動畫效果,可並行

所以此方案適用 可預測的動畫 的場景

結語

雖然React-Native標榜的就是性能更好,但也只是跟Web對比而言,跟Native比還是有不少差距的,跟Xamarin等跨平台方案對比性能也差距不小,所以在開發時還是要關注下性能問題,性能調優還是要花不少精力去解決的。

微粉iOS:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM