有一種通過CAAnimation實現(xiàn)的協(xié)議叫做CAMediaTiming,也就是CABasicAnimation和CAKeyframeAnimation的基類(指CAAnimation)告喊。像duration,beginTime和repeatCount這些時間相關的屬性都在這個類中影锈。大體而言粉怕,協(xié)議中定義了8個屬性匕争,這些屬性通過一些方式結合在一起,準確的控制著時間麸粮。文檔中每個屬性只有幾句話半哟,所以很有可能在看這篇文章之前你都已經(jīng)讀過了酬滤,但是我覺得使用可視化的圖形能更好的解釋時間签餐。
可視化的CAMediaTiming
為了顯示相關屬性的不同時間,無論是他們自己還是混合狀態(tài)盯串,我都會動態(tài)的將橙色變?yōu)樗{色氯檐。下面的塊狀顯示了從開始到結束的動畫過程,時間線上每一個標志代表一秒鐘体捏。你可以看到時間線上的任意一點冠摄,當前顏色即表示動畫中的當前時間。比如译打,duration像下面一樣可視耗拓。
一旦動畫完成后,CAAnimation默認從layer上移除奏司。這從上面的圖形中也表現(xiàn)出來了乔询。一旦動畫達到最終值,它會從layer上移除韵洋。如果layer的顏色是橙色(開始的顏色)竿刁,那么顏色又會便會橙色。在這個可視化界面中搪缨,layer的顏色是白色食拜,所以你也可以看到動畫加入layer后的兩秒鐘又會變白,因為那是動畫已經(jīng)結束了副编。
我們也形象的描述一下動畫的beginTime负甸,這樣讓人更容易理解。
durations設置為1.5秒了呻待,開始時間設為當前時間。(CACurrentMediaTime())加一秒队腐,所以動畫在2.5s后結束蚕捉。動畫加入到layer上之后,花費一秒鐘時間來啟動并呈現(xiàn)出來柴淘。結果是1+1.5=2.5
為了讓動畫從fromValue開始顯示迫淹,你可以將動畫設置為fill backwards。我們可以通過設置fillMode為kCAFillModeBackwards为严。
autoreverses屬性可以產(chǎn)生從初始值到最終值敛熬,并反過來回到初始值的動畫。這意味著動畫發(fā)生了兩次第股。
和repeatCount比起來荸型,repeatCount可以將動畫重復兩次(如下所示)或者任意次(你甚至可以使用像1.5這樣的分數(shù)來完成一個半動畫)。一旦動畫達到它的最終值,他就會立馬跳回到初始值并重新開始
和repeat count類似瑞妇,但很少用到的就是repeat duration了。它將會根據(jù)給定的一個duration簡單的重復動畫(如下2秒所示)梭冠。經(jīng)過一個repeat duration時辕狰,如果它小于動畫的duration,那么動畫就會提前結束(repeat duration之后結束)
這些都可以組合起來將一個反轉動畫重復多次或在一個給定的duration間重復控漠。
一個跟時間相關有趣的屬性是speed蔓倍。通過設置duration為3秒,但是speed為2盐捷,動畫快速的執(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秒的動畫膨俐。
動畫開始運行時跳過第一秒進入從橙色到藍色的過度,直接運行剩下的兩秒焚刺,直到完全變藍敛摘。然后動畫直接跳回完全橙色的時候,并完成第一秒的顏色轉換乳愉。這看起來有點像我們把動畫的第一秒切下來兄淫,然后放到最后。
這個屬性很少用蔓姚,但是它可以和一個暫停的動畫(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的背景色
拉動刷新
你還可以使用另一種機制來控制動畫時間:像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];
結果是:下拉視圖時,可以直接控制動畫的進度您宪。如果你抬起手動畫將會退回去。
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;
}];
最終奠涌,當你向下拖動超過臨界值時便會像這樣