Flutter 動(dòng)畫(huà)詳解(一)

本文主要介紹了動(dòng)畫(huà)的原理相關(guān)概念,對(duì)其他平臺(tái)的動(dòng)畫(huà)做了一個(gè)簡(jiǎn)要的梳理,并簡(jiǎn)要的介紹了Flutter動(dòng)畫(huà)的一些知識(shí)。

1. 動(dòng)畫(huà)介紹

動(dòng)畫(huà)對(duì)于App來(lái)說(shuō),非常的重要。很多App,正是因?yàn)橛辛藙?dòng)畫(huà),所以才會(huì)覺(jué)得炫酷。移動(dòng)端的動(dòng)畫(huà)庫(kù)有非常的多,例如iOS上的Pop、web端的animate.css、Android端的AndroidViewAnimations、跨平臺(tái)的Lottie等。正是因?yàn)橛辛诉@些封裝好的動(dòng)畫(huà)庫(kù),我們制作酷炫的效果方便了不少。當(dāng)然了,這些庫(kù)都是基于各平臺(tái)基礎(chǔ)的動(dòng)畫(huà)API實(shí)現(xiàn)的,筆者今天要聊的,也就是基礎(chǔ)的動(dòng)畫(huà)及背后的原理。

1.1 動(dòng)畫(huà)的本質(zhì)

動(dòng)畫(huà)顧名思義,就是動(dòng)起來(lái)的畫(huà)面。畫(huà)面為什么會(huì)動(dòng)起來(lái)了呢?在回答這個(gè)問(wèn)題之前,我們先引入一個(gè)概念。

人眼在觀察景物時(shí),光信號(hào)傳入大腦神經(jīng),需經(jīng)過(guò)一段短暫的時(shí)間,光的作用結(jié)束后,視覺(jué)形象并不立即消失,這種殘留的視覺(jué)稱“后像”,視覺(jué)的這一現(xiàn)象則被稱為“視覺(jué)暫留”。

視覺(jué)暫留被認(rèn)為是電影的最重要的一個(gè)理論基礎(chǔ)。我們看到的動(dòng)畫(huà),實(shí)際上是一連串的畫(huà)面組成,只不過(guò)是以很快的速度去播放,人眼在下一個(gè)畫(huà)面出來(lái)之前,還殘留著上一個(gè)畫(huà)面的視覺(jué),看起來(lái)就像是在沒(méi)有間隔的播放這一系列的圖片,也就是我們稱之為的動(dòng)畫(huà)。

1.2 相關(guān)概念

動(dòng)畫(huà)會(huì)有很多相關(guān)的概念,理解了這些概念,會(huì)對(duì)實(shí)際的使用更有幫助。

1.2.1 幀

剛才在介紹動(dòng)畫(huà)本質(zhì)的時(shí)候,用到了畫(huà)面這個(gè)詞匯,只是方便讀者去理解,這個(gè)畫(huà)面,在學(xué)術(shù)上叫做。

幀就是影像動(dòng)畫(huà)中最小單位的單幅影像畫(huà)面,一幀就是一副靜止的畫(huà)面。

幀里面又分為關(guān)鍵幀和過(guò)渡幀,這兩概念是理解一些動(dòng)畫(huà)的基礎(chǔ),例如Android中的補(bǔ)間動(dòng)畫(huà)。在一些場(chǎng)景中,我們可能不會(huì)給出一個(gè)動(dòng)畫(huà)的所有幀,所以將幀分成關(guān)鍵幀和過(guò)渡幀。關(guān)鍵幀可以理解為一個(gè)動(dòng)畫(huà)的起始狀態(tài),而過(guò)渡幀則是系統(tǒng)自動(dòng)完成插在關(guān)鍵幀之間的部分。

關(guān)鍵幀與過(guò)渡幀

我們知道Android中的補(bǔ)間動(dòng)畫(huà),基礎(chǔ)的有四種類型,平移、縮放、旋轉(zhuǎn)、透明度。而我們?cè)O(shè)置動(dòng)畫(huà)的時(shí)候,通常只是設(shè)置起始的狀態(tài),也就是關(guān)鍵幀,中間過(guò)程其實(shí)我們并不需要去考慮,如果關(guān)注動(dòng)畫(huà)速率的話,頂多加一個(gè)差值器去控制,但是中間生成的幀我們并沒(méi)有提供。

系統(tǒng)為什么能夠補(bǔ)齊過(guò)渡幀呢?我們看下這四種基本的動(dòng)畫(huà)類型,給定起始狀態(tài),中間狀態(tài)我們其實(shí)是可以通過(guò)計(jì)算推演出來(lái)的,這也是系統(tǒng)為什么能夠補(bǔ)齊的原因。

是不是只有這四種才可以通過(guò)系統(tǒng)填補(bǔ)過(guò)渡幀呢?顯然不是的,例如一個(gè)跳躍前進(jìn)的動(dòng)畫(huà),添加一些限制條件,就可以推演出中間的狀態(tài)。系統(tǒng)提供的只是比較常見(jiàn)的四種,并不是說(shuō)只有這四種,而是絕大部分動(dòng)畫(huà)都可以通過(guò)這四種組合實(shí)現(xiàn)。當(dāng)然了,肯定也是有實(shí)現(xiàn)不了的,這個(gè)時(shí)候有一個(gè)辦法就是通過(guò)canvas畫(huà)出來(lái)。

另外再插一嘴,Android系統(tǒng)提供的四種動(dòng)畫(huà)操作,也是變換矩陣是四維的原因,具體的就不多說(shuō)了,之前文章也有介紹過(guò)。

最后一嘴,此處講解幀的概念,拿了很多Android相關(guān)的知識(shí)去講解,只是希望讀者能夠通過(guò)一些已知的概念,去理解一些未知的。動(dòng)畫(huà)的原理都一樣,具體到某個(gè)平臺(tái),可能頂多就是實(shí)現(xiàn)或者叫法不一樣罷了。

1.2.2 幀數(shù)與FPS

小時(shí)候很多人都玩過(guò)書(shū)角動(dòng)畫(huà)。在書(shū)或者本子的一角,每一頁(yè)都畫(huà)上一個(gè)畫(huà)面,然后撥書(shū)角,不同速度撥,動(dòng)畫(huà)的感受不一樣,撥的越快,動(dòng)畫(huà)越流暢。這是為什么呢?這就牽扯到幀數(shù)與FPS了。

幀數(shù),幀的數(shù)量。FPS(Frame per Second),即每秒顯示幀數(shù)。

這兩個(gè)概念,主要是FPS有什么作用呢?這是因?yàn)槿搜凵順?gòu)造的原因。人眼殘留鏡像的時(shí)間是有限的,如果過(guò)了這個(gè)時(shí)間,下一幀還沒(méi)有變化,就會(huì)感覺(jué)不流暢。但也不是幀數(shù)越大越好,畢竟人眼也是有極限的。

幀數(shù)不同的感覺(jué)

1.2.3 插值器

如果動(dòng)畫(huà)播放一直都是這種勻速的進(jìn)行,那表現(xiàn)形式就太單一了。那如何實(shí)現(xiàn)非線性的動(dòng)畫(huà)效果呢,這個(gè)時(shí)候就需要用到插值器了。

插值器其實(shí)并不復(fù)雜,就是一個(gè)數(shù)學(xué)函數(shù),設(shè)置屬性值從初始值過(guò)渡到結(jié)束值的變化規(guī)律。每個(gè)平臺(tái)都有自己定義好的一系列插值器,可以供開(kāi)發(fā)者選擇使用,也提供自定義的接口,本質(zhì)上是一個(gè)貝塞爾函數(shù)。

一個(gè)勻速插值器如下:

屬性值百分比 = 時(shí)間百分比

1.3 如何實(shí)現(xiàn)

動(dòng)畫(huà)的基本原理和一些基本概念都介紹了一下,現(xiàn)在來(lái)聊一下動(dòng)畫(huà)的實(shí)現(xiàn)。

先拋開(kāi)系統(tǒng)層級(jí)的各種渲染優(yōu)化,也僅僅是以補(bǔ)間動(dòng)畫(huà)為例,假設(shè)以現(xiàn)有的移動(dòng)平臺(tái)基礎(chǔ)上,去實(shí)現(xiàn)一套簡(jiǎn)單的動(dòng)畫(huà)框架,該如何去實(shí)現(xiàn)呢?

以Android的為例,要實(shí)現(xiàn)平移、縮放、旋轉(zhuǎn)、透明度這四種基礎(chǔ)的補(bǔ)間動(dòng)畫(huà),可以看到,這些都是基于某個(gè)屬性的動(dòng)畫(huà),平移是基于point、縮放是基于scale、旋轉(zhuǎn)是基于angle、透明度是基于alpha。

結(jié)合插值器,提煉出一個(gè)通用的動(dòng)畫(huà)類,這個(gè)類的作用是根據(jù)插值器,得到視圖某個(gè)時(shí)間點(diǎn)的屬性變化的狀態(tài)。

既然各個(gè)時(shí)間點(diǎn)的狀態(tài)已經(jīng)有了,剩下來(lái)的就是讓各個(gè)狀態(tài)渲染出來(lái)。底層的機(jī)制在此處不去討論,這個(gè)地方就需要一個(gè)定時(shí)器,定時(shí)器的作用是每隔一段時(shí)間就把素材渲染到屏幕上。

至此,一個(gè)簡(jiǎn)易的動(dòng)畫(huà)框架就出來(lái)了。如果對(duì)各平臺(tái)比較了解的話,就知道我說(shuō)的是視圖動(dòng)畫(huà),真正的動(dòng)畫(huà)引擎不是這么簡(jiǎn)單,涉及到的技術(shù)也比較復(fù)雜,但是大體的思想不會(huì)有錯(cuò),不管是哪種動(dòng)畫(huà),都是跟時(shí)間相關(guān)的幀序列,只是實(shí)現(xiàn)方式不同。

這也是筆者為什么花這么多篇幅去介紹動(dòng)畫(huà)相關(guān)的概念,知道一些底層原理后,不管什么平臺(tái),怎么去實(shí)現(xiàn),底層的思想肯定都差不多,只是實(shí)現(xiàn)上的不同。

2. 其他平臺(tái)的動(dòng)畫(huà)

Flutter動(dòng)畫(huà),與Android、iOS等平臺(tái)對(duì)比,其實(shí)本身并沒(méi)有什么特別之處。基本的原理是一樣的,只是提供的種類以及實(shí)現(xiàn)的方式不同罷了。

2.1 Android動(dòng)畫(huà)

Android的動(dòng)畫(huà),大的分類有兩種:

  • 視圖動(dòng)畫(huà)(View Animation)
  • 屬性動(dòng)畫(huà)(Property Animation)

視圖動(dòng)畫(huà)又可以分為兩類:

  • 補(bǔ)間動(dòng)畫(huà)(Tween Animation)
  • 逐幀動(dòng)畫(huà)(Frame Animation)

這之間的差別是什么呢?它們只有實(shí)現(xiàn)上的差別

  • 補(bǔ)間動(dòng)畫(huà)是根據(jù)初始狀態(tài),系統(tǒng)自動(dòng)補(bǔ)充中間狀態(tài);
  • 逐幀動(dòng)畫(huà)則是需要我們提供每一幀;
  • 視圖動(dòng)畫(huà)只是作用于視圖上,而不會(huì)改變控件的屬性;
  • 屬性動(dòng)畫(huà)則是會(huì)實(shí)實(shí)在在的更改控件的屬性。

可以看出Android的動(dòng)畫(huà)分類還是比較明晰的。

2.2 iOS動(dòng)畫(huà)

iOS很久沒(méi)弄了,在這里也簡(jiǎn)單說(shuō)下,不對(duì)的話還請(qǐng)各位指正。

  • 隱式動(dòng)畫(huà)
  • 顯式動(dòng)畫(huà)

顯式動(dòng)畫(huà)又可以分為兩類:

  • 基礎(chǔ)動(dòng)畫(huà)
  • 關(guān)鍵幀動(dòng)畫(huà)

這些動(dòng)畫(huà)類別之間的差別是什么呢?

  • 隱式動(dòng)畫(huà),顧名思義是不指定動(dòng)畫(huà)類型,更改某個(gè)屬性,Core Animation來(lái)決定如何且何時(shí)去做動(dòng)畫(huà);
  • 基礎(chǔ)動(dòng)畫(huà),根據(jù)起始值來(lái)做動(dòng)畫(huà);
  • 關(guān)鍵幀動(dòng)畫(huà),則是定義一系列關(guān)鍵幀,系統(tǒng)自動(dòng)補(bǔ)齊中間的過(guò)渡幀。

通過(guò)動(dòng)畫(huà)這一塊兒,可以看出iOS的分類其實(shí)是比較的模糊的,有一些歷史包袱。

2.3 css動(dòng)畫(huà)

css動(dòng)畫(huà)大體上有兩種:

  • Transition
  • Animation

web中的動(dòng)畫(huà)分類簡(jiǎn)單的多了

  • Transition動(dòng)畫(huà),給定起始值,可以結(jié)合插值器做動(dòng)畫(huà);
  • Animation動(dòng)畫(huà),則是定義一系列關(guān)鍵幀,系統(tǒng)補(bǔ)齊中間的過(guò)渡幀。

2.4 小節(jié)

通過(guò)上面?zhèn)€平臺(tái)動(dòng)畫(huà)粗略的介紹,動(dòng)畫(huà)在不同平臺(tái)雖然被叫著不同的名稱,本質(zhì)上其實(shí)都差不多的,變來(lái)變?nèi)ザ际沁@幾種方式,要么根據(jù)屬性要么根據(jù)關(guān)鍵幀,要么更改繪制層,要么更改控件本身屬性。一些游戲引擎,雖然我沒(méi)有看,但是我覺(jué)得原理也大致相似。

3. Flutter動(dòng)畫(huà)

上面鋪墊了這么多,終于到Flutter動(dòng)畫(huà)了。Flutter是一門比較新的技術(shù),歷史包袱理應(yīng)說(shuō)是最小的。

3.1 Flutter動(dòng)畫(huà)分類

Flutter動(dòng)畫(huà)分為兩類:

  • 補(bǔ)間動(dòng)畫(huà)(Tween Animation)
  • 基于物理的動(dòng)畫(huà)(Physics-based animation)

補(bǔ)間動(dòng)畫(huà)很好理解,基于物理的動(dòng)畫(huà)是這個(gè)什么鬼。

基于物理的動(dòng)畫(huà)是一種遵循物理學(xué)定律的動(dòng)畫(huà)形式

舉個(gè)例子,比方說(shuō)你滑動(dòng)一張圖片,這個(gè)過(guò)程不是勻速的,而是起始速度快,然后慢慢的降速,就像一本書(shū)在地上往前推一樣。它有什么特點(diǎn)呢?

  • 遵循物理學(xué)定律;
  • 能夠依據(jù)加速度和速度去計(jì)算和更新每一幀的動(dòng)畫(huà)數(shù)值;
  • 當(dāng)受力平衡時(shí),動(dòng)畫(huà)為處于恒定運(yùn)動(dòng)或靜止?fàn)顟B(tài)。

哈哈,最后一點(diǎn)是不是似曾相識(shí),這樣做的好處是什么呢?隨著人們生活水平的極大提升,移動(dòng)端硬件這些年也是趕英超美,人們不再滿足于簡(jiǎn)單的動(dòng)畫(huà),于是就有部分有(xian)識(shí)(de)之(dan)士(teng),實(shí)現(xiàn)了基于物理學(xué)定律的動(dòng)畫(huà)。

這種動(dòng)畫(huà)iOS或者Android有沒(méi)有呢,是有的,但不是作為最基礎(chǔ)的動(dòng)畫(huà)API被提供。為什么其他平臺(tái)沒(méi)有將這個(gè)納入最基本的動(dòng)畫(huà)中去呢?

  • 歷史原因。iOS以及Android端多年前就誕生了,那個(gè)時(shí)候,硬件資源都是極其有限的,當(dāng)時(shí)的環(huán)境不足以支撐這種動(dòng)畫(huà)效果。但也不是說(shuō)沒(méi)有,一些游戲引擎里面也是有的,但是作為操作系統(tǒng),把這些集成進(jìn)去,還是不太現(xiàn)實(shí)的。
  • 認(rèn)知過(guò)程。電腦以及移動(dòng)端這些年的發(fā)展,最開(kāi)始只是滿足于查看最簡(jiǎn)單的文本,然后各種圖片視頻。隨著互聯(lián)網(wǎng)的越來(lái)越普及,人們的需求越來(lái)越多了。于是,在一些游戲里面才會(huì)見(jiàn)到的基于物理學(xué)定律的動(dòng)畫(huà),進(jìn)入了尋常百姓家。反觀一下,現(xiàn)在也是有非常多的“委屈”事物。例如人類幾千年都是通過(guò)人眼看現(xiàn)實(shí)的事物,現(xiàn)在卻被限制在一個(gè)小屏幕上,這其實(shí)是不合理的。所以AR、VR,還有一些動(dòng)畫(huà)片科幻片中的遠(yuǎn)程感知等技術(shù),才會(huì)層出不窮,當(dāng)然這個(gè)扯的有些遠(yuǎn)了。

基于物理的動(dòng)畫(huà)這么好,那有什么好處呢?更自然,更加符合人們的認(rèn)知。

3.2 分類的原因

前面講的各平臺(tái)的動(dòng)畫(huà),從本質(zhì)上看,基于某個(gè)屬性也好,幀動(dòng)畫(huà)也好,都是從一種狀態(tài)到另一種狀態(tài),而中間過(guò)程是可以推演出來(lái)的,所以Flutter提供補(bǔ)間動(dòng)畫(huà)。

基于物理的動(dòng)畫(huà),我猜測(cè)可能是為了實(shí)現(xiàn)其他平臺(tái)上的一些效果,例如彈簧、阻尼效果等等。所以Flutter就提供了這種動(dòng)畫(huà)API,畢竟沒(méi)什么包袱。

3.3 動(dòng)畫(huà)模式

Flutter提煉了三種動(dòng)畫(huà)模式,與其說(shuō)提煉出來(lái)的,倒不如說(shuō)統(tǒng)一不能更為合適。

  • list、grid中的動(dòng)畫(huà)(Animated list or grid)。場(chǎng)景是item的添加或者刪除操作;
  • 轉(zhuǎn)場(chǎng)動(dòng)畫(huà)(Shared element transition)。場(chǎng)景是當(dāng)前頁(yè)面打開(kāi)另一頁(yè)面的過(guò)渡動(dòng)畫(huà);
  • 交錯(cuò)動(dòng)畫(huà)(Staggered animation)。場(chǎng)景是需要部分或者完全交錯(cuò)的動(dòng)畫(huà)。

3.4 復(fù)雜度

Flutter的實(shí)現(xiàn)原理以及這個(gè)階段,注定了做動(dòng)畫(huà)是非常麻煩的一件事情??缙脚_(tái)的技術(shù)做動(dòng)畫(huà)都麻煩,這個(gè)似乎是通識(shí),為了跨平臺(tái)而同化的一些東西,到異化部分,就變得蛋疼了,動(dòng)畫(huà)正是這種存在。

Flutter做動(dòng)畫(huà)復(fù)雜提現(xiàn)在哪些地方呢?

  • 實(shí)現(xiàn)的動(dòng)畫(huà)較少,這個(gè)是初期,沒(méi)啥好說(shuō)的;
  • 動(dòng)畫(huà)實(shí)現(xiàn)的方式復(fù)雜,這個(gè)是Flutter的設(shè)計(jì)思想所決定的。

4. 小節(jié)

關(guān)于動(dòng)畫(huà)的具體的實(shí)現(xiàn)、一些底層的代碼邏輯以及如何使用,將會(huì)在下一篇文章中做介紹。這篇文章更多的是偏于一些普適性的介紹,關(guān)于Flutter動(dòng)畫(huà)相關(guān)的介紹反而很少。希望讀者能夠了解一些動(dòng)畫(huà)的原理,以及各個(gè)平臺(tái)動(dòng)畫(huà)的大致實(shí)現(xiàn)方式,這樣可以更好的理解Flutter動(dòng)畫(huà)的設(shè)計(jì)思想。文中若有錯(cuò)誤的地方,還懇請(qǐng)指出,在此不勝感激。

5. 后話

筆者建了一個(gè)Flutter學(xué)習(xí)相關(guān)的項(xiàng)目,Github地址,里面包含了筆者寫(xiě)的關(guān)于Flutter學(xué)習(xí)相關(guān)的一些文章,會(huì)定期更新,也會(huì)上傳一些學(xué)習(xí)Demo,歡迎大家關(guān)注。

6. 參考

  1. 電影原理
  2. 視覺(jué)暫留
  3. iOS-Core-Animation-Advanced-Techniques
  4. CSS動(dòng)畫(huà)簡(jiǎn)介
  5. Animations in Flutter
  6. Android 中基于物理特性的動(dòng)畫(huà)簡(jiǎn)介
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,323評(píng)論 25 708
  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 14,101評(píng)論 2 59
  • 1、通過(guò)CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明AI閱讀 16,228評(píng)論 3 119
  • 每周的星期一都是最忙碌也最充實(shí)的一天,從上午的私人心理顧問(wèn)學(xué)習(xí)小組,到下午的讀書(shū)會(huì),到晚上的成長(zhǎng)小組,每一個(gè)環(huán)節(jié)都...
    志玲覺(jué)知生活閱讀 822評(píng)論 0 2
  • 我儂你儂兩相融,愛(ài)卿芳閣春意濃。 南苑今夜巫山去,燕子復(fù)鳴叫天明。 天蠶錦緞掩酥胸,地動(dòng)山搖顯猩紅。 可憐嬌...
    安六清閱讀 533評(píng)論 1 1

友情鏈接更多精彩內(nèi)容