CAMediaTiming 詳解

有一種通過CAAnimation實現(xiàn)的協(xié)議叫做CAMediaTiming,也就是CABasicAnimation和CAKeyframeAnimation的基類(指CAAnimation)告喊。像duration,beginTime和repeatCount這些時間相關的屬性都在這個類中影锈。大體而言粉怕,協(xié)議中定義了8個屬性匕争,這些屬性通過一些方式結合在一起,準確的控制著時間麸粮。文檔中每個屬性只有幾句話半哟,所以很有可能在看這篇文章之前你都已經(jīng)讀過了酬滤,但是我覺得使用可視化的圖形能更好的解釋時間签餐。

可視化的CAMediaTiming

為了顯示相關屬性的不同時間,無論是他們自己還是混合狀態(tài)盯串,我都會動態(tài)的將橙色變?yōu)樗{色氯檐。下面的塊狀顯示了從開始到結束的動畫過程,時間線上每一個標志代表一秒鐘体捏。你可以看到時間線上的任意一點冠摄,當前顏色即表示動畫中的當前時間。比如译打,duration像下面一樣可視耗拓。

Figure 1.設置duration為1.5秒

一旦動畫完成后,CAAnimation默認從layer上移除奏司。這從上面的圖形中也表現(xiàn)出來了乔询。一旦動畫達到最終值,它會從layer上移除韵洋。如果layer的顏色是橙色(開始的顏色)竿刁,那么顏色又會便會橙色。在這個可視化界面中搪缨,layer的顏色是白色食拜,所以你也可以看到動畫加入layer后的兩秒鐘又會變白,因為那是動畫已經(jīng)結束了副编。

我們也形象的描述一下動畫的beginTime负甸,這樣讓人更容易理解。

Figure 2.設置duration為1.5秒痹届,開始時間為1.0秒

durations設置為1.5秒了呻待,開始時間設為當前時間。(CACurrentMediaTime())加一秒队腐,所以動畫在2.5s后結束蚕捉。動畫加入到layer上之后,花費一秒鐘時間來啟動并呈現(xiàn)出來柴淘。結果是1+1.5=2.5

為了讓動畫從fromValue開始顯示迫淹,你可以將動畫設置為fill backwards。我們可以通過設置fillMode為kCAFillModeBackwards为严。

Figure 3.Fill mode可以讓動畫從fromValue開始顯示

autoreverses屬性可以產(chǎn)生從初始值到最終值敛熬,并反過來回到初始值的動畫。這意味著動畫發(fā)生了兩次第股。

Figure 4.Autoreverses使得動畫結束后又回到起始狀態(tài)

和repeatCount比起來荸型,repeatCount可以將動畫重復兩次(如下所示)或者任意次(你甚至可以使用像1.5這樣的分數(shù)來完成一個半動畫)。一旦動畫達到它的最終值,他就會立馬跳回到初始值并重新開始

Figure 5.Repeat count可以讓動畫運行超過一次

和repeat count類似瑞妇,但很少用到的就是repeat duration了。它將會根據(jù)給定的一個duration簡單的重復動畫(如下2秒所示)梭冠。經(jīng)過一個repeat duration時辕狰,如果它小于動畫的duration,那么動畫就會提前結束(repeat duration之后結束)

Figure 6.Repeat duration會讓動畫根據(jù)一個給定duration重復

這些都可以組合起來將一個反轉動畫重復多次或在一個給定的duration間重復控漠。

Figure 7.組合

一個跟時間相關有趣的屬性是speed蔓倍。通過設置duration為3秒,但是speed為2盐捷,動畫快速的執(zhí)行了1.5秒偶翅,因為它的速度是之前的兩倍。

Figure 8.速度為2時碉渡,動畫執(zhí)行速度是之前的兩倍聚谁,所以3秒的動畫只需要執(zhí)行1.5秒

如果只是配置了一個簡單的動畫,那么你也可以分開使用beginTime和duration以達到相同的效果滞诺。但是使用speed屬性的優(yōu)點在于這兩個事實:

1.動畫的speed是分等級的形导。(hierarchical)

2.CAAnimation不是唯一一個實現(xiàn)CAMediaTiming的類。

Hierarchical speed

速度為2的動畫組有一部分動畫的速度為1.5习霹,那么這個動畫就是3倍于正常速度朵耕。

CAMediaTiming的其他實現(xiàn)

CAMediaTiming是CAAnimation實現(xiàn)的一個協(xié)議,但是CALayer(所有Core Animationlayers的基類)也實現(xiàn)了相同的協(xié)議淋叶,這就意味著你可以設置layer的speed為2.0阎曹,這樣,所有加入到layer的動畫運行都要快兩倍煞檩。同樣的处嫌,如果一個速度為3的動畫加到一個速度為0.5的layer上,這個動畫最終將會以1.5倍的常速運行形娇。

為了控制動畫或layer的速度锰霜,通常還可以設置speed為0,從而暫停動畫桐早。和timeOffset結合在一起時癣缅,可以通過像slider類似的控件控制動畫,我們在下文中也會講到哄酝。

剛開始timeOffset屬性是非常奇怪的友存。正如名字所示那樣,它對時間進行偏移(offset)陶衅,從而計算出動畫的狀態(tài)屡立。如下圖所示。duration為3秒搀军,offset為1秒的動畫膨俐。

Figure 9.你可以offset整個動畫勇皇,但是動畫所有部分任然會執(zhí)行

動畫開始運行時跳過第一秒進入從橙色到藍色的過度,直接運行剩下的兩秒焚刺,直到完全變藍敛摘。然后動畫直接跳回完全橙色的時候,并完成第一秒的顏色轉換乳愉。這看起來有點像我們把動畫的第一秒切下來兄淫,然后放到最后。

這個屬性很少用蔓姚,但是它可以和一個暫停的動畫(speed=0)結合在一起控制’current time’捕虽。一個暫停的動畫停留在第一幀。如果你觀察offset動畫每次的第一個顏色坡脐,你可以看到它的顏色值一秒就進入顏色轉換泄私。將time offset設置為其他值,你可以讓那段時間進入轉換挨措。

控制動畫時間

同時使用speed和timeOffset可以控制動畫的當前時間挖滤。這幾乎不會涉及到什么代碼,但是概念卻比較難以理解(我希望插圖能有所幫助)浅役。為了方便斩松,我將動畫的duration設為1.0。因為time offset是絕對值觉既。這樣做就意味著當time offset為0.0時惧盹,此時就是動畫的0%處(動畫開始),time offset為1.0時瞪讼,就是動畫的100%處(動畫結束)钧椰。

Slider

以一個簡單的例子開始,我們?yōu)橐粋€layer的背景色創(chuàng)建一個基本的動畫并增加到layer上符欠。將layer的速度設為0以暫停動畫嫡霞。

CABasicAnimation *changeColor =

[CABasicAnimation?animationWithKeyPath:@"backgroundColor"];

changeColor.fromValue?=?(id)[UIColor?orangeColor].CGColor;

changeColor.toValue???=?(id)[UIColor?blueColor].CGColor;

changeColor.duration??=?1.0;?//?For?convenience

[self.myLayer?addAnimation:changeColor

forKey:@"Change?color"];

self.myLayer.speed?=?0.0;?//?Pause?the?animation

當拖動slider時,在action方法中將slider的值(將slider的值設為0-1)設為layer的time offset

- (IBAction)sliderChanged:(UISlider *)sender {

self.myLayer.timeOffset?=?sender.value;?//?Update?"current?time"

}

下面給出了效果圖:當拖動slider時動畫的值便會改變希柿,并且更新layer的背景色

Figure 10.layer的顏色隨著slider的值改變而改變

拉動刷新

你還可以使用另一種機制來控制動畫時間:像scroll事件诊沪。這樣可以創(chuàng)建一個自定義下拉刷新動畫,當達到加載新數(shù)據(jù)的臨界值之前曾撤,用戶的拖拉操作都會產(chǎn)生一個動畫端姚。在我的這個例子中,scroll事件控制著一個路徑畫筆的動畫挤悉。當達到臨界值時渐裸,將會啟動另一種動畫暗示新數(shù)據(jù)正在加載中。

這次我們使用scroll view向下拖動的總量來控制時間,為了標準化昏鹃,這個值將會以points的形式尚氛,這樣是非常好的,因為我們需要設置一個拖動的臨界值來判斷何時開始加載更多的數(shù)據(jù)洞渤。像下面那樣處理代碼怠褐。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView

{

CGFloat?offset?=

scrollView.contentOffset.y+scrollView.contentInset.top;

if?(offset?<=?0.0?&&?!self.isLoading)?{

CGFloat?startLoadingThreshold?=?60.0;

CGFloat?fractionDragged???????=?-offset/startLoadingThreshold;

self.pullToRefreshShape.timeOffset?=?MAX(0.0,?fractionDragged);

if?(fractionDragged?>=?1.0)?{

[self?startLoading];

}

}

}

像這樣控制動畫:

CABasicAnimation *writeText =

[CABasicAnimation?animationWithKeyPath:@"strokeEnd"];

writeText.fromValue?=?@0;

writeText.toValue?=?@1;

CABasicAnimation?*move?=

[CABasicAnimation?animationWithKeyPath:@"position.y"];

move.byValue?=?@(-22);

move.toValue?=?@0;

CAAnimationGroup?*group?=?[CAAnimationGroup?animation];

group.duration?=?1.0;

group.animations?=?@[writeText,?move];

結果是:下拉視圖時,可以直接控制動畫的進度您宪。如果你抬起手動畫將會退回去。

Figure 11.使用scroll事件直接控制拖動刷新

self.isLoading = YES;

// start the loading animation

[self.loadingShape addAnimation:[self loadingAnimation]

forKey:@"Write that word"];

CGFloat contentInset? ? = self.collectionView.contentInset.top;

CGFloat indicatorHeight = CGRectGetHeight(self.loadingIndicator.frame);

// inset the top to keep the loading indicator on screen

self.collectionView.contentInset =

UIEdgeInsetsMake(contentInset+indicatorHeight, 0, 0, 0);

self.collectionView.scrollEnabled = NO; // no further scrolling

[self loadMoreDataWithAnimation:^{

// during the reload animation (where new cells are inserted)

self.collectionView.contentInset =

UIEdgeInsetsMake(contentInset, 0, 0, 0);

self.loadingIndicator.alpha = 0.0;

} completion:^{

// reset everything

[self.loadingShape removeAllAnimations];

self.loadingIndicator.alpha = 1.0;

self.collectionView.scrollEnabled = YES;

self.pullToRefreshShape.timeOffset = 0.0; // back to the start

self.isLoading = NO;

}];

最終奠涌,當你向下拖動超過臨界值時便會像這樣

Figure 12.拖動刷新和加載動畫
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末宪巨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子溜畅,更是在濱河造成了極大的恐慌捏卓,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慈格,死亡現(xiàn)場離奇詭異怠晴,居然都是意外死亡,警方通過查閱死者的電腦和手機浴捆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門蒜田,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人选泻,你說我怎么就攤上這事冲粤。” “怎么了页眯?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵梯捕,是天一觀的道長。 經(jīng)常有香客問我窝撵,道長傀顾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任碌奉,我火速辦了婚禮短曾,結果婚禮上,老公的妹妹穿的比我還像新娘道批。我一直安慰自己错英,他們只是感情好,可當我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布隆豹。 她就那樣靜靜地躺著椭岩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上判哥,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天献雅,我揣著相機與錄音,去河邊找鬼塌计。 笑死挺身,一個胖子當著我的面吹牛,可吹牛的內容都是我干的锌仅。 我是一名探鬼主播章钾,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼热芹!你這毒婦竟也來了贱傀?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤伊脓,失蹤者是張志新(化名)和其女友劉穎府寒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體报腔,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡株搔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了纯蛾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纤房。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖茅撞,靈堂內的尸體忽然破棺而出帆卓,到底是詐尸還是另有隱情,我是刑警寧澤米丘,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布剑令,位于F島的核電站,受9級特大地震影響拄查,放射性物質發(fā)生泄漏吁津。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一堕扶、第九天 我趴在偏房一處隱蔽的房頂上張望碍脏。 院中可真熱鬧,春花似錦稍算、人聲如沸典尾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钾埂。三九已至河闰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間褥紫,已是汗流浹背姜性。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留髓考,地道東北人部念。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像氨菇,于是被迫代替她去往敵國和親儡炼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內容