使用方法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
兩個屬性就能夠了。3d
transformAnima.removedOnCompletion = NO; transformAnima.fillMode = kCAFillModeForwards;
解釋:爲何動畫結束後返回原狀態?
首先咱們須要搞明白一點的是,layer動畫運行的過程是怎樣的?其實在咱們給一個視圖添加layer動畫時,真正移動並非咱們的視圖自己,而是 presentation layer 的一個緩存。動畫開始時 presentation layer開始移動,原始layer隱藏,動畫結束時,presentation layer從屏幕上移除,原始layer顯示。這就解釋了爲何咱們的視圖在動畫結束後又回到了原來的狀態,由於它根本就沒動過。代理
這個一樣也能夠解釋爲何在動畫移動過程當中,咱們爲什麼不能對其進行任何操做。code
因此在咱們完成layer動畫以後,最好將咱們的layer屬性設置爲咱們最終狀態的屬性,而後將presentation layer 移除掉。orm
[self.imageView.layer addAnimation:transformAnima forKey:@"A"];
須要注意的兩點對象
addAnimation:forKey:
是將 CABasicAniamtion 對象進行了 copy 操做的。因此在將其添加到一個layer上以後,咱們仍是將其再次添加到另外一個layer上的。該屬性定義了你的動畫在開始和結束時的動做。默認值是 kCAFillModeRemoved
。blog
取值的解釋事件
也便是屬性timingFunction
值的設定,有種方式來獲取屬性值圖片
functionWithName:
這種方式很簡單,這裏只是簡單說明一下取值的含義:
kCAMediaTimingFunctionLinear 傳這個值,在整個動畫時間內動畫都是以一個相同的速度來改變。也就是勻速運動。
kCAMediaTimingFunctionEaseIn 使用該值,動畫開始時會較慢,以後動畫會加速。
kCAMediaTimingFunctionEaseOut 使用該值,動畫在開始時會較快,以後動畫速度減慢。
kCAMediaTimingFunctionEaseInEaseOut 使用該值,動畫在開始和結束時速度較慢,中間時間段內速度較快。
functionWithControlPoints: : : :
實現,這個以後再說,佔個坑先。removedOnCompletion
屬性爲NOfillMode
儘可能取默認值就行了,不要去設置它的值。只有在極個別的狀況下咱們會修改它的值,之後會說到,這裏先佔個坑。直接上代碼
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(@"旋轉動畫執行結束"); } }
因爲CAAnimation的delegate使用的strong類型,
因此在全局變量以下設置時會產生循環引用的狀況
self.animation.delegate = self;//可經過複用dealloc方法來驗證
解決方案
//.h #import <UIKit/UIKit.h> @interface AnimationDelegate : NSObject @end //.m #import "AnimationDelegate.h" @implementation AnimationDelegate - (void)animationDidStart:(CAAnimation *)anim { NSLog(@"Animation Start"); } - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { NSLog(@"Animation Stop"); } - (void)dealloc { NSLog(@"Delegate Dealloc"); } @end
使用方式
self.animation.delegate = [[AnimationDelegate alloc]init];
NSProxy
來解決YYWeakProxy
類self.animation.delegate = [YYWeakProxy proxyWithTarget:self];
值 | 說明 | 使用形式 |
---|---|---|
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之間的 |