iOS開發之動畫中的時間(概況)

一、引言

在iOS開發中使用動畫時,可以通過設置動畫的durationspeedbegintimeoffset屬性,來設置動畫的時長、速度、起始時間及起始偏移。
用一個簡單的例子來說明各個參數的的作用。動畫很簡單,一個紅色的方塊從左移到右邊。動畫的持續時間是1s,沒有重復,效果如下。

原動畫-w181

    
    CFTimeInterval currentTime = CACurrentMediaTime();
    CFTimeInterval currentTimeInLayer = [self.testLayer convertTime:currentTime fromLayer:nil];
    CFTimeInterval addTime = currentTimeInLayer;
    anim.beginTime = 0.3 + addTime;
    [anim setTimeOffset:0.5];
    [anim setSpeed:2];

做修改以后,效果如下:

修改以后的動畫-w181

與上面相比,三處不同

  1. 動畫的速度是原來的兩倍。
  2. 點擊開始動畫的按鈕,到開始動畫,有一個延遲。
  3. 動畫起始時,滑塊的位置為中央,而不是在左邊。

我們已經看到了這些屬性的效果。翻閱文檔,發現begintimespeed等屬性是CAMediaTiming這協議的屬性,并且CALayerCAAnimation都遵守了CAMediaTiming協議。
那么CAMediaTiming協議是什么呢?有什么作用呢?

二、層級時間結構

根據文檔,CMediaTiming協議構建了一個層級的時間系統,并用這個層級的時間系統來協調各個layer、animation的時間。
這個協議被CAAnimationCALayer遵守,每一個遵守協議的的object對應一個time space。根據object之間的關系,不同的time space有層級關系。比如Layer A有一個subLayer B,那么Layer A對應的time space就是layer B對應的time spaceparent time space。每一個time space中時間的數值都是根據parent time space的數值,以及begintimespeed等屬性,根據一定的規則來計算的。
為了便于理解層級時間系統,先看下layer在屏幕上的顯示位置是如何確定的,然后做一個類比。

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

  1. 確定window layer在屏幕位置position1
  2. 根據position1及view layer的position屬性,確定view layer在屏幕中的位置position2
  3. 根據position2及sublayer1的position屬性,確定sublayer1在屏幕中的位置position3

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

  1. 確定window layer中的time1
  2. 根據time1及view layer的begintimeoffset等屬性計算出view layer中的time2
  3. 根據time2及sublayer1的begintimeoffset等屬性計算出sublayer中的time3

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

  1. 層級時間系統的構成復雜。
    layer tree的每一級都是CALayer,而只要遵守CAMediaTiming協議,就可以作為層級時間系統的一部分。比如CALayerCAAnimation(及其子類CAAnimationGroup)都可以作為層級時間系統的一部分。
  2. 不同層級之間時間轉換規則復雜
    計算當前layer的位置時,只需要知道父layer的位置,以及當前layer的position屬性。計算當前層級時間時,不僅需要知道上一個層級的時間,還需要知道當前層級的begintimeoffsetspeed等屬性。轉換的規則也比較復雜,要經歷兩次轉換。從parent timeactive local time,再到basic local time

三、active local time

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

  1. begin time
    子層級相對于父層級的起始時間。也就是父層級的時間經過多久,子層級才開始計算時間。
    比如子層級A被加入層級時間系統時,它父層級B的時間是5s,子層級A的begintime是6s,那么當它父層級的時間變為6s時,子層級才開始計算時間。
  2. speed
    子層級相對于父層級的時間流逝速度。如果speed是2,那么當父層級的時間增加了10s時,子層級的時間增加了20s(10s的2倍)。
  3. timeOffset
    為本地時間增加一個偏移。 如果timeOffset是5s,那么本地時間的起始就是5s。

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

t = (tp - begin) * speed + offset

四、basic local time

這次轉換是為了處理當前層級的重放(repeat)、以及重放之前是否要倒放(play backward)等操作。
比如當前層級是一個動畫(CAAnimation遵守CAMediaTiming協議),duration是1s,經過第一次轉換之后的active local time是5.5s。如果動畫的repeatCount是10,那么經過第二次轉化以后,basic local time會是0.5s,因此當前是動畫展示一半的狀態。

  1. repeatCountrepeatDuration
    當前的層級要重復的次數或重復的時間,兩者不可同時指定。
    以動畫為例,如果指定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協議后,可以實現很多動畫的效果。

  1. 讓某一個layer上的動畫停止
    設置layer的speed為0即可。
  2. 實現門打開然后關閉的效果
    實現一個門打開的動畫,然后把動畫的autoreverses屬性設置為YES即可。
  3. layer上的若干動畫依次延遲啟動
    分別設置這些動畫的beginTime為不同的值即可
  4. 手動控制動畫的進度
    設置動畫的speed為0,然后改變動畫的offset即可。

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

參考

控制動畫時間
控制動畫時間(上文的中文版)
Time Warp in Animation

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,551評論 6 30
  • 書寫的很好,翻譯的也棒!感謝譯者,感謝感謝! iOS-Core-Animation-Advanced-Techni...
    錢噓噓閱讀 2,315評論 0 6
  • 轉載地址:談談iOS Animation 零.前言 這里沒有太多的代碼細節,只是探索iOS動畫的基本概念,以及其抽...
    木夜溯閱讀 2,429評論 0 4
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺iOS動畫全貌。在這里你可以看...
    F麥子閱讀 5,141評論 5 13
  • 1. 在協作中,你只是一個統籌者,任何的成功,都要虛心的感謝協助你完成好這些的同事們,你能做到的,他們一點都不比你...
    tree閱讀 162評論 0 1