天天看點

iOS 開發之動畫中的時間

在iOS開發中使用動畫時,可以通過設定動畫的duration、speed、begintime、offset屬性,來設定動畫的時長、速度、起始時間及起始偏移。

用一個簡單的例子來說明各個參數的的作用。動畫很簡單,一個紅色的方塊從左移到右邊。動畫的持續時間是1s,沒有重複,效果如下。

iOS 開發之動畫中的時間

做修改以後,效果如下:

iOS 開發之動畫中的時間

與上面相比,三處不同

動畫的速度是原來的兩倍。

點選開始動畫的按鈕,到開始動畫,有一個延遲。

動畫起始時,滑塊的位置為中央,而不是在左邊。

我們已經看到了這些屬性的效果。翻閱文檔,發現begintime、speed等屬性是CAMediaTiming這協定的屬性,并且CALayer、CAAnimation都遵守了CAMediaTiming協定。

那麼CAMediaTiming協定是什麼呢?有什麼作用呢?

根據文檔,CMediaTiming協定建構了一個層級的時間系統,并用這個層級的時間系統來協調各個layer、animation的時間。

這個協定被CAAnimation及CALayer遵守,每一個遵守協定的的object對應一個time space。根據object之間的關系,不同的time space有層級關系。比如Layer A有一個subLayer B,那麼Layer A對應的time space就是layer B對應的time space的parent time space。每一個time space中時間的數值都是根據parent time space的數值,以及begintime、speed等屬性,根據一定的規則來計算的。

為了便于了解層級時間系統,先看下layer在螢幕上的顯示位置是如何确定的,然後做一個類比。

iOS 開發之動畫中的時間

layer層級如上。要确定sublayer1在螢幕上的顯示位置,一共分三步。

确定window layer在螢幕位置position1

根據position1及view layer的position屬性,确定view layer在螢幕中的位置position2

根據position2及sublayer1的position屬性,确定sublayer1在螢幕中的位置position3

與此類似,要确定sub1ayer1中的time,也要分三步。

确定window layer中的time1

根據time1及view layer的begintime、offset等屬性計算出view layer中的time2

根據time2及sublayer1的begintime、offset等屬性計算出sublayer中的time3

和确定layer的位置相比,确定時間有一些複雜,主要提現在下面兩點

1 . 層級時間系統的構成複雜。

layer tree的每一級都是CALayer,而隻要遵守CAMediaTiming協定,就可以作為層級時間系統的一部分。比如CALayer、CAAnimation(及其子類CAAnimationGroup)都可以作為層級時間系統的一部分。

2 .不同層級之間時間轉換規則複雜

計算目前layer的位置時,隻需要知道父layer的位置,以及目前layer的position屬性。計算目前層級時間時,不僅需要知道上一個層級的時間,還需要知道目前層級的begintime、offset、speed等屬性。轉換的規則也比較複雜,要經曆兩次轉換。從parent time到active local time,再到basic local time。

這次轉換是為了處理目前層級的object在父層級的的時間線上的位置,以及目前層級和父層級之間時間流逝速度的關系。

和這次轉換相關的屬性有beginTime、speed以及timeOffset

begin time

子層級相對于父層級的起始時間。也就是父層級的時間經過多久,子層級才開始計算時間。

比如子層級A被加入層級時間系統時,它父層級B的時間是5s,子層級A的begintime是6s,那麼當它父層級的時間變為6s時,子層級才開始計算時間。

speed

子層級相對于父層級的時間流逝速度。如果speed是2,那麼當父層級的時間增加了10s時,子層級的時間增加了20s(10s的2倍)。

timeOffset

為本地時間增加一個偏移。 如果timeOffset是5s,那麼本地時間的起始就是5s。

從parent time到active local time有一個公式,可以用來參考。

這次轉換是為了處理目前層級的重放(repeat)、以及重放之前是否要倒放(play backward)等操作。

比如目前層級是一個動畫(CAAnimation遵守CAMediaTiming協定),duration是1s,經過第一次轉換之後的active local time是5.5s。如果動畫的repeatCount是10,那麼經過第二次轉化以後,basic local time會是0.5s,是以目前是動畫展示一半的狀态。

1 .repeatCount及repeatDuration

目前的層級要重複的次數或重複的時間,兩者不可同時指定。

以動畫為例,如果指定repeatCount,那麼指定了動畫要重複幾次。如果指定了repeatDuration,那麼指定了動畫重複的時間。

2 .autoreverses

在重複之前是否要倒放。

根據這些知識,可以解釋文章開始時設定參數的效果。

當動畫被加到layer上時,動畫對應的time space被加到層級時間系統中,是layer對應的time space的子層級。

1 .動畫的速度是原來的兩倍

設定動畫的speed是2,這樣子動畫中的時間流逝速度時layer中時間流逝速度的2倍。當layer中時間經過0.5s時,動畫中時間已經流逝了1s,動畫已經完成了。(動畫的duration是1s)

2 .點選開始動畫的按鈕,到開始動畫,有一個延遲

我們首先得到了目前layer的時間addtime,然後把動畫的begintime設定為addtime+0.3。這樣子當動畫被加到layer之後0.3s,layer中的時間是addtime+0.3,此時動畫中的時間才開始計算,之前動畫沒有開始。

3 .動畫起始時,滑塊的位置為中央,而不是在左邊

我們設定了動畫的offset為0.5s。當動畫開始時,動畫對應的time space的時間是0.5s,對應動畫duration的一半,即滑塊位置在螢幕中央。

了解了CAMediaTiming協定後,可以實作很多動畫的效果。

讓某一個layer上的動畫停止

設定layer的speed為0即可。

實作門打開然後關閉的效果

實作一個門打開的動畫,然後把動畫的autoreverses屬性設定為YES即可。

layer上的若幹動畫依次延遲啟動

分别設定這些動畫的beginTime為不同的值即可

手動控制動畫的進度

設定動畫的speed為0,然後改變動畫的offset即可。

蘋果已經把工具給我們了,可以做出什麼樣的産品就看大家的想象力了。

控制動畫時間: http://ronnqvi.st/controlling-animation-timing/

Time Warp in Animation:http://wangling.me/2011/06/time-warp-in-animation.html#fn-1