CoreAnimation
在我以前的UIKit動畫裏面簡單的提了一句CoreAnimation動畫,其實你們別看它類庫名種有個animation,實際上animation在這個庫中只佔有很小的地位。多線程
像咱們常常用的邊框、圓角、陰影、錨點等等這些屬性都是有CA提供的。動畫
在說CA動畫前,咱們先說一下CALayer這個類,CALayer能夠叫作圖層,UIView是視圖。對別CALayer和UIView它們之間最大的差異在於CALayer是不處理交互的,好比點擊事件等。spa
實際上UIView是CALayer的高層封裝罷了,UIView的現實、繪圖、動畫等等都是封裝的CALayer,在CALayer中有個重要的屬性叫作affineTransform(放射變換),其實它和UIView中的transform是一摸同樣的,返回的都是線程
CAAffineTransform。當你改變過一個view.transform屬性或者view.layer.transform的時候須要恢復默認狀態的話,記得先把他 們重置可使用代理
view.transform = CGAffineTransformIdentity,或者view.layer.transform =CATransform3DIdentity,假設你一直不斷的改變一個view.transform的屬性,而每次改變以前沒有重置的話,你會發現後來 的改變和你想要的發生變化了,不是你真正想要的結果。code
如今你們對CALayer有了初步的認識,咱們一塊兒看看動畫在CA中是如何使用的。orm
隱式動畫對象
其實咱們只要修改CALayer中和動畫有關的屬性,就算咱們不寫動畫代碼,在運行的時候也是會有動畫效果的。這叫作隱式動畫,也就是咱們並無明顯的調用。blog
下面咱們看個例子事件
@interface ViewController () { CALayer *_viewLayer; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _viewLayer = [CALayer layer]; _viewLayer.frame = CGRectMake(0, 0, 100, 100); [_viewLayer setBackgroundColor:[UIColor greenColor].CGColor]; _viewLayer.opacity = 0.25; [self.view.layer addSublayer:_viewLayer]; // Do any additional setup after loading the view, typically from a nib. } - (IBAction)click:(id)sender { CGAffineTransform moveTransforam = CGAffineTransformMakeTranslation(180, 200); [_viewLayer setAffineTransform:moveTransforam]; _viewLayer.opacity = 1; }
把這段代碼輸入,點擊按鈕,你就會發現view逐漸的變的不透明,而且位置也發生了改變。
顯式動畫
在顯式動畫中,不須要修改屬性和調用動畫執行方法,只須要經過CABasicAnimation逐個定義就好了,每一個對象有持續時間、重複次數等屬性,而後使用addAnimation:forkey:方法分別將每一個動畫用到圖層的特定屬性中。
可以作動畫的圖層屬性有如下:
opacity;
transform.scale;
transform.scale.x;
transform.scale.y;
transform.rotation.z;
opacity;
margin;
zPosition;
backgroundColor;
cornerRadius;
bounds;
contents;
contentsRect;
frame;
hidden;
mask;
masksToBounds;
position;
shadowColor;
shadowOffset;
shadowOpacity;
shadowRadius;
下面咱們看一個顯式動畫的例子:
CABasicAnimation *opAnim = [CABasicAnimation animationWithKeyPath:@"opacity"]; opAnim.duration = 3.0; opAnim.fromValue = [NSNumber numberWithFloat:.25]; opAnim.toValue = [NSNumber numberWithFloat:1.0]; opAnim.cumulative = NO; opAnim.repeatCount = 2; opAnim.fillMode = kCAFillModeForwards; opAnim.removedOnCompletion = NO; [_viewLayer addAnimation:opAnim forKey:@"animateOpacity"]; CGAffineTransform moveTransform = CGAffineTransformMakeTranslation(180, 200); CABasicAnimation *moveAnim = [CABasicAnimation animationWithKeyPath:@"transform"]; moveAnim.duration = 6.0; moveAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeAffineTransform(moveTransform)]; moveAnim.fillMode = kCAFillModeForwards; moveAnim.removedOnCompletion = NO; moveAnim.delegate = self; moveAnim.repeatCount = 2; [_viewLayer addAnimation:moveAnim forKey:@"animateTransform"];
把click中的代碼換成上面的代碼,會發現視圖慢慢變得不透明,過程當中執行兩次。
下面看一下CABasicAnimation屬性有哪些做用:
屬性 | 描述 |
duration | 動畫持續時間 |
fromValue | 動畫的屬性起始值 |
toValue | 動畫的屬性目標值 |
cumulative | 是否保留上次動畫的值 |
repeatCount | 重複次數 |
fillMode | 使用動畫後不在返回原位置 |
removeOnCompletion | 動畫完成後移除動畫狀態 |
delegate | 動畫代理 |
這裏簡單說一下cumulative,上面例子若是cumulative設爲YES的話,就不會執行第二次的opacity的變化了,由於保留了動畫的狀態。
fillMode和removeOnCompletion一塊兒用使得動畫結束後視圖還在結束的位置,不然視圖會回到原始位置。
不過這裏說一下,雖然咱們看到的值是已經變了,可是實際上原始值並不會由於作了動畫而改變,只不過是affineTransform變了,若是要屢次作affineTransform就要像上面說的,須要讓它恢復初始值就不會出問題。
而後再來看看delegate,不過代理不是CABasicAnimation的,也不是它的父類CAPropertyAnimation的,而是它父類的父類CAAnimation的!
代理方法以下
- (void)animationDidStart:(CAAnimation *)anim; - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
一個是動畫是在動畫開始時的回調,另外一個是在動畫結束後的回調。
關鍵幀動畫
關鍵幀動畫其實也能夠說又分兩種,一種是幀動畫一種是路徑動畫。
幀動畫,很少說先看例子
CAKeyframeAnimation *opAnim = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; opAnim.duration = 6.0; opAnim.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.25],[NSNumber numberWithFloat:0.75],[NSNumber numberWithFloat:1.0], nil]; opAnim.keyTimes = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0],[NSNumber numberWithFloat:0.5],[NSNumber numberWithFloat:1.0], nil]; opAnim.fillMode = kCAFillModeForwards; opAnim.removedOnCompletion = NO; opAnim.delegate = self; [_viewLayer addAnimation:opAnim forKey:@"animateOpacity"];
這裏咱們對透明度作動畫,分別在values和keyTimes裏面設置了到達某一時間應該到達的值,也就是經過這些值影響了在不一樣時間動畫的狀態不同。你們應該還記得在以前的UIKit動畫中,介紹過keyframe開始和持續時間的含義,它們都是總時間的百分比。
路徑動畫
路徑動畫動畫其實能夠說是特殊的幀動畫,首先動畫的對象屬性是position,而後每一幀的速率都相同,用多線程的概念來說大概就是串行執行動畫的意思。
CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, 160.f, 100.f); CGPathAddLineToPoint(path, NULL, 100.f, 280.f); CGPathAddLineToPoint(path, NULL, 260.f, 170.f); CGPathAddLineToPoint(path, NULL, 60.f, 170.f); CGPathAddLineToPoint(path, NULL, 220.f, 280.f); CGPathCloseSubpath(path); CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"]; [anim setDuration:10.f]; [anim setDelegate:self]; [anim setPath:path]; CFRelease(path); path = nil; [_viewLayer addAnimation:anim forKey:@"position"];
這裏用CGMutablePathRef來產生路徑上下文,其實CGMutablePathRef和繪圖時的CGContextRef差很少。
下面設置再也不是針對values和keyTimes了,而是設置它的path屬性。
最後不要忘了釋放CGMutablePathRef,由於它是CoreFoundation對象沒有采用ARC因此要手動管理內存。