標籤:
概述
在動畫中,我們會指定動畫的期間。例如
scaleAnimation.duration = self.config.appearDuration
那麼這個時間是怎麼定義的呢?是指的絕對時間嗎?
層級時間結構
layer在螢幕上的顯示位置是根據父layer的位置以及本身相對於父layer位移定義的。
與此類似,每一個layer都有自己的time space,計算本地時間(local time)時候,需要根據父layer的時間以及一定的轉換規則來計算出本地時間。
這個規則就是CAMediaTiming協議。每一個CALayer和CAAnimation實現了這個協議。
?
?
關於時間的概念
- 絕對時間
Absolute time
由CACurrentMediaTime函數返回,實際調用mach_absolute_time()。
active local time
根據CAMediaTiming協議計算得到的當前對象上的時間。
basic local time
由於動畫可以重複(repeat)或者回放(play backwards)。需要把active local time轉化為做動畫相關的時間。
例如active local time是5.5s,動畫的重複次數是10,動畫期間是1s。那麼5.5s的active local time對應的local time是0.5s。
CAMediaTiming協議
beginTime
Required. Specifies the begin time of the receiver in relation to its parent object, if applicable.
指定了指定了父物件時間和子物件時間的位移。
speed
Specifies how time is mapped to receiver’s time space from the parent time space
對動畫以及子動畫速度應用一個縮放的因子。如果speed是2.0,那麼本地時間流逝的速度是父物件的時間流逝速度的兩倍。
timeOffset
Required. Specifies an additional time offset in active local time.
對本地時間做了一個位移。
時間轉換公式
- 從父layer轉化為active local time\[ t= max\left\{(t_p-begintime),0\right\}*speed+offset \]其中\(t\)是本地時間,\(t_p\)是父layer的時間,其他都是
CAMediaTiming要求實現的欄位。
例子
用一個簡單的例子來說明各個參數的影響。動畫很簡單,一個紅色的方塊從左移到右邊。動畫的期間是1s,沒有重複。
?
- 設定speed為2,begin time為0.3s,offset為0.5s,效果如下
?
與上面相比,三處不同
- 動畫的速度是原來的兩倍,這是因為動畫的speed是2。
- 動畫起始時,滑塊的位置為中央,而不是在左邊。這是因為offset為0.5s。由於動畫的期間是1s,0.5s時,動畫剛剛進行了一半,滑塊的位置是在螢幕中央。
- 點擊開始動畫的按鈕,到開始動畫,有一個延遲,這是因為begin time的時間不是預設值,而是有一個0.3s的延遲。
- 時間變換的映像表示
- 從父layer的時間到子layer的active local time
?
圖中,直線的斜率是speed,第一個y值不為零的點,對應的橫軸座標是begintime,對應的y軸座標是offset
- 從active local time到basic local time?圖中,不為0的部分的x軸長度,即是動畫時間,由repeattime或repeatDuration指定。由於這個動畫沒有repeattime或repeatDuration,因此就是動畫的duration。如果指定了動畫的時間,比如repeatcount為3,那麼非0部分會重複3次。
如果指定了autoreverses為yes,那麼折線會部分有負的曲率。
第一個不為0的點對應的橫軸座標即為offset。fillMode可以理解為不在動畫時間內的y值是什麼。如果kCAFillModeBackwards,對應於橫軸在offset之前時,縱軸對應於offset。kCAFillModeForwards對應於橫軸在動畫結束之後,縱軸儲存不變。
- 父物件和子物件聯動
我們的例子中,動畫是加在layer上的,它們都遵守CAMediatiming協議,就CAMediatiming看來,動畫的父物件是layer。
- 設定父物件的speed
我們設定layer的speed為2,動畫的speed為0.1,實際的速度會是0.2.?
- 設定父物件的offset設定父物件的offset為0.5,那麼動畫將會在一半處開始。
?
關於begintime
根據公式
\[
t= max\left\{(t_p-begintime),0\right\}*speed+offset
\]
這裡begintime是應該怎麼指定呢?如果想把一個加到layer的動畫的延遲5s執行,應該把begintime直接設為5嗎?
由於begintime是相對於父物件(layer)的時間位移。由於layer可能在很久以前就存在了,因此對於動畫來說\(t_p\)是一個很大的值。直接把begintime指定為5s,那麼\(t\)將會是一個很大的值。正確的做法是把begintime設定為5s+這個layer被加到父layer以後,度過的時間,稱為addtime.
animation.beginTime = addTime + delay;
如何得到addtime
addTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
參考
控制動畫時間
控制動畫時間
Time Warp in Animation
iOS開發之動畫中的時間