使用方法animationWithKeyPath:
對 CABasicAnimation進行實例化,並指定Layer的屬性做爲關鍵路徑進行註冊。緩存
//圍繞y軸旋轉CABasicAnimation *transformAnima = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
duration | 動畫的時長 |
repeatCount | 重複的次數。不停重複設置爲 HUGE_VALF |
repeatDuration | 設置動畫的時間。在該時間內動畫一直執行,不計次數。 |
beginTime | 指定動畫開始的時間。從開始延遲幾秒的話,設置爲【CACurrentMediaTime() + 秒數】 的方式 |
timingFunction | 設置動畫的速度變化 |
autoreverses | 動畫結束時是否執行逆動畫 |
fromValue | 所改變屬性的起始值 |
toValue | 所改變屬性的結束時的值 |
byValue | 所改變屬性相同起始值的改變量 |
transformAnima.fromValue = @(M_PI_2); transformAnima.toValue = @(M_PI); transformAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; transformAnima.autoreverses = YES; transformAnima.repeatCount = HUGE_VALF; transformAnima.beginTime = CACurrentMediaTime() + 2;
只需設置removedOnCompletion
、fillMode
兩個屬性就能夠了。動畫
transformAnima.removedOnCompletion = NO; transformAnima.fillMode = kCAFillModeForwards;
解釋:爲何動畫結束後返回原狀態?
首先咱們須要搞明白一點的是,layer動畫運行的過程是怎樣的?其實在咱們給一個視圖添加layer動畫時,真正移動並非咱們的視圖自己,而是 presentation layer 的一個緩存。動畫開始時 presentation layer開始移動,原始layer隱藏,動畫結束時,presentation layer從屏幕上移除,原始layer顯示。這就解釋了爲何咱們的視圖在動畫結束後又回到了原來的狀態,由於它根本就沒動過。spa
這個一樣也能夠解釋爲何在動畫移動過程當中,咱們爲什麼不能對其進行任何操做。代理
因此在咱們完成layer動畫以後,最好將咱們的layer屬性設置爲咱們最終狀態的屬性,而後將presentation layer 移除掉。code
[self.imageView.layer addAnimation:transformAnima forKey:@"A"];
須要注意的兩點orm
一個 CABasicAniamtion 的實例對象只是一個數據模型,和他綁定到哪個layer上是沒有關係的對象
方法addAnimation:forKey:
是將 CABasicAniamtion 對象進行了 copy 操做的。因此在將其添加到一個layer上以後,咱們仍是將其再次添加到另外一個layer上的。事件
該屬性定義了你的動畫在開始和結束時的動做。默認值是 kCAFillModeRemoved
。圖片
取值的解釋ci
kCAFillModeRemoved 設置爲該值,動畫將在設置的 beginTime 開始執行(如沒有設置beginTime屬性,則動畫當即執行),動畫執行完成後將會layer的改變恢復原狀。
kCAFillModeForwards 設置爲該值,動畫即便以後layer的狀態將保持在動畫的最後一幀,而removedOnCompletion的默認屬性值是 YES,因此爲了使動畫結束以後layer保持結束狀態,應將removedOnCompletion設置爲NO。
kCAFillModeBackwards 設置爲該值,將會當即執行動畫的第一幀,不管是否設置了 beginTime屬性。觀察發現,設置該值,剛開始視圖不見,還不知道應用在哪裏。
kCAFillModeBoth 該值是 kCAFillModeForwards 和 kCAFillModeBackwards的組合狀態
也便是屬性timingFunction
值的設定,有種方式來獲取屬性值
functionWithName:
這種方式很簡單,這裏只是簡單說明一下取值的含義:
kCAMediaTimingFunctionLinear 傳這個值,在整個動畫時間內動畫都是以一個相同的速度來改變。也就是勻速運動。
kCAMediaTimingFunctionEaseIn 使用該值,動畫開始時會較慢,以後動畫會加速。
kCAMediaTimingFunctionEaseOut 使用該值,動畫在開始時會較快,以後動畫速度減慢。
kCAMediaTimingFunctionEaseInEaseOut 使用該值,動畫在開始和結束時速度較慢,中間時間段內速度較快。
functionWithControlPoints: : : :
實現,這個以後再說,佔個坑先。repeatCount 設置動畫的執行次數
autoreverses 默認值爲 NO,將其設置爲 YES
speed 改變更畫的速度 能夠直接設置動畫上的speed屬性,這樣只有這個動畫速度。
animation.speed = 2;
或者在layer上設置speed屬性,這樣在該視圖上的全部動畫都提速,該視圖上的全部子視圖上的動畫也會提速。
speed兩點需注意的:
(1) 若是設置動畫時間爲4s,speed設置爲2,則動畫只需2s便可執行完。
(2)若是同時設置了動畫的speed和layer 的speed,則實際的speed爲二者相乘。
在動畫執行完成以後,最好仍是將動畫移除掉。也就是儘可能不要設置removedOnCompletion
屬性爲NO
fillMode
儘可能取默認值就行了,不要去設置它的值。只有在極個別的狀況下咱們會修改它的值,之後會說到,這裏先佔個坑。
解決有時視圖會閃動一下的問題,咱們能夠將layer的屬性值設置爲咱們的動畫最後要達到的值,而後再給咱們的視圖添加layer動畫。
直接上代碼
CABasicAnimation *positionAnima = [CABasicAnimation animationWithKeyPath:@"position.y"]; positionAnima.duration = 0.8; positionAnima.fromValue = @(self.imageView.center.y); positionAnima.toValue = @(self.imageView.center.y-30); positionAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; positionAnima.repeatCount = HUGE_VALF; positionAnima.repeatDuration = 2; positionAnima.removedOnCompletion = NO; positionAnima.fillMode = kCAFillModeForwards; [self.imageView.layer addAnimation:positionAnima forKey:@"AnimationMoveY"];
CABasicAnimation *positionAnima = [CABasicAnimation animationWithKeyPath:@"position.y"]; positionAnima.fromValue = @(self.imageView.center.y); positionAnima.toValue = @(self.imageView.center.y-30); positionAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];CABasicAnimation *transformAnima = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"]; transformAnima.fromValue = @(0); transformAnima.toValue = @(M_PI); transformAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];CAAnimationGroup *animaGroup = [CAAnimationGroup animation]; animaGroup.duration = 2.0f; animaGroup.fillMode = kCAFillModeForwards; animaGroup.removedOnCompletion = NO; animaGroup.animations = @[positionAnima,transformAnima]; [self.imageView.layer addAnimation:animaGroup forKey:@"Animation"];
爲了獲取動畫的開始和結束事件,須要實現協議
positionAnima.delegate = self;
代理方法實現
//動畫開始時- (void)animationDidStart:(CAAnimation *)anim { NSLog(@"開始了"); }//動畫結束時- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { //方法中的flag參數代表了動畫是天然結束仍是被打斷,好比調用了removeAnimationForKey:方法或removeAnimationForKey方法,flag爲NO,若是是正常結束,flag爲YES。 NSLog(@"結束了"); }
其實比較重要的是有多個動畫的時候如何在代理方法中區分不一樣的動畫
兩種方式
若是咱們添加動畫的視圖是全局變量,可以使用該方法。
添加動畫時,咱們使用了
[self.imageView.layer addAnimation:animaGroup forKey:@"Animation"];
因此,可根據key來區分不一樣的動畫
//動畫開始時- (void)animationDidStart:(CAAnimation *)anim { if ([anim isEqual:[self.imageView.layer animationForKey:@"Animation"]]) { NSLog(@"動畫組執行了"); } }
Note:把動畫存儲爲一個屬性而後再回調中比較,用來斷定是哪一個動畫是不可行的。應爲委託傳入的動畫參數是原始值的一個深拷貝,不是同一個值
添加動畫的視圖是局部變量時,可以使用該方法
添加動畫給動畫設置key-value對
[positionAnima setValue:@"PositionAnima" forKey:@"AnimationKey"]; [transformAnima setValue:@"TransformAnima" forKey:@"AnimationKey"];
因此,能夠根據key中不一樣的值來進行區分不一樣的動畫
//動畫結束時- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { if ([[anim valueForKey:@"AnimationKey"]isEqualToString:@"PositionAnima"]) { NSLog(@"位置移動動畫執行結束"); } else if ([[anim valueForKey:@"AnimationKey"]isEqualToString:@"TransformAnima"]){ NSLog(@"旋轉動畫執行結束"); } }
transform.scale | 比例轉化 | @(0.8) |
transform.scale.x | 寬的比例 | @(0.8) |
transform.scale.y | 高的比例 | @(0.8) |
transform.rotation.x | 圍繞x軸旋轉 | @(M_PI) |
transform.rotation.y | 圍繞y軸旋轉 | @(M_PI) |
transform.rotation.z | 圍繞z軸旋轉 | @(M_PI) |
cornerRadius | 圓角的設置 | @(50) |
backgroundColor | 背景顏色的變化 | (id)[UIColor purpleColor].CGColor |
bounds | 大小,中心不變 | [NSValue valueWithCGRect:CGRectMake(0, 0, 200, 200)]; |
position | 位置(中心點的改變) | [NSValue valueWithCGPoint:CGPointMake(300, 300)]; |
contents | 內容,好比UIImageView的圖片 | imageAnima.toValue = (id)[UIImage imageNamed:@"to"].CGImage; |
opacity | 透明度 | @(0.7) |
contentsRect.size.width | 橫向拉伸縮放 | @(0.4)最好是0~1之間的 |
self.saomiao.layer.anchorPoint = CGPointMake(1,1);//以右下角爲原點轉,(0,0)是左上角轉,(0.5,0,5)心中間轉,其它以此類推
/*
frame.origin.x = position.x - anchorPoint.x * bounds.size.width;
frame.origin.y = position.y - anchorPoint.y * bounds.size.height;
*/
rotation.removedOnCompletion = false