Upload
weizhong-yang
View
894
Download
0
Embed Size (px)
Citation preview
今天用到的Sample Code
https://github.com/zonble/CAShowcase
New BSD License
Monday, March 28, 2011
Why CoreAnimation?
• 這年頭動畫效果非常重要,尤其是 iPad
• 當 UIView 提供的動畫不夠用的時候,又還不需要用到自己寫 OpenGL,就該用 CoreAnimation 了。
Monday, March 28, 2011
CoreAnimation 是?
• 一套 Mac/iOS framework
• 製作各種平面動畫• UIView 動畫其實算是 CoreAnimation 的
wrapper
Monday, March 28, 2011
使用 CoreAnimation 的挑戰
• 要習慣 concurrent 的程式寫作
• 不過,反正做軟體最難的部份往往都不是程式…
Monday, March 28, 2011
使用 CoreAnimation的挑戰
• 難的往往是設計與溝通• 在設計階段很難用 Mockup 溝通-怎麼講都很難讓對方理解最後會產生什麼動畫,除非把程式寫出來…
• 如果不是對方要的,那程式就白寫了…
Monday, March 28, 2011
使用 CoreAnimation
• 都是 Objective-C 物件
• 可喜可賀
Monday, March 28, 2011
重要的 Class
• CALayer:演員
• CAAnimation:腳本
• CATransaction:整體情境設定
Monday, March 28, 2011
第一步
• #import <QuartzCore/QuartzCore.h>
Monday, March 28, 2011
CALayer
Monday, March 28, 2011
CALayer
• iOS
• 每個 UIView 都有一個 layer([aView layer] or aView.layer)
• Mac
• NSView 要特別設定 setWantsLayer:
• 今天以 iOS 為主
Monday, March 28, 2011
CALayer 的 Interface 很像 View
• 有 frame、bounds、background color
• 把一個 layer 放到另外一個 layer 上面,是用 addSublayer
• 加入之後,也可以知道自己的 superlayer
Monday, March 28, 2011
CALayer 也不像 View
• 不是 responder,不處理各種 event(Click、Touch…)
• 大部分 property 一改就會產生動畫
• 繪製內容的方法也稍微不一樣
Monday, March 28, 2011
設定 CALayer
• CALayer *aLayer = [CALayer layer];
• aLayer.contents = (id)[UIImage imageNamed:@”test.jpg”].CGImage;
• 設定圖片內容時,其實就已經有 fade in/out 效果
Monday, March 28, 2011
設定 CALayer
• aLayer.position = CGPointMake()...
• aLayer.bounds = CGRectMake()...
• 都會直接產生動畫效果• 預設動畫時間為 0.25 秒
Monday, March 28, 2011
產生動畫的方法
• 直接改 Layer 的 property 就會有動畫
• 自己使用 CAAnimation 物件做動畫
• 後面再講…
Monday, March 28, 2011
CATransaction 1
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
// 調整 CALayer
[CATransaction commit];
// 這樣會關閉各種動畫效果
Monday, March 28, 2011
CATransaction 2[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:2.0] forKey: kCATransactionAnimationDuration];
// 調整 CALayer
[CATransaction commit];
// 這樣會改變動畫時間
Monday, March 28, 2011
先提一下 CATransition…
CATransition *t = [CATransition animation];
t.type = kCATransitionMoveIn
t.subtype = kCATransitionFromRight;
aLayer.contents = (id)[UIImage imageNamed:@”test.jpg”].CGImage;
[aLayer addAnimation:t forKey:@"Transition"];
// 產生移動效果
Monday, March 28, 2011
CATransition
• 有很多 Private API(flip、cube)
• 用了會不會被 reject? 呃… 不知道。
Monday, March 28, 2011
CAAnimation
Monday, March 28, 2011
CAAnimation
• CABasicAnimation
• CAKeyframeAnimation
• CAAnimationGroup
• CATransition …前面講了
Monday, March 28, 2011
CABasicAnimation
• [CABasicAnimation animationWithKeyPath:...]
• @”position”
• @”bounds”
• @”opacity”
• @”contents”...
Monday, March 28, 2011
CABasicAnimation
• 還有• @”transform.rotation.x”
• @”transform.rotation.y”
• @”transform.rotation.z”
• ...
Monday, March 28, 2011
CABasicAnimation
• fromValue = [NSValue...];
• toValue = [NSValue ...];
• duration = 3.0; //Seconds
• repeatCount = NSUIntegerMax; // Forever
Monday, March 28, 2011
CAKeyframeAnimation
• 不是用 fromValue、toValue,而是用 CGPathRef
• CAKeyframeAnimation *a =[CAKeyframeAnimation animationWithKeyPath:@"position"];
• a.path = (CGPathRef)path;
Monday, March 28, 2011
CAAnimationGroup
• CAAnimationGroup *group = [CAAnimationGroup animation];
• group.animations = [NSArray arrayWithObjects:anim1, anim2, nil];
Monday, March 28, 2011
執行 CAAnimation
• [aLayer addAnimation:myAnimation forKey:@"MyKey"];
Monday, March 28, 2011
fill mode
• 一個動畫結束,預設 layer 會跳回到動畫前的狀態
• animation.fillMode = kCAFillModeForwards;
• 這樣才會在結束的時候不動…
Monday, March 28, 2011
另外要注意一下Property 的改變
CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@”bounds”];
a.fromValue = [NSValue valuwWithCGRect:fromRect];
a.toValue = [NSValue valuwWithCGRect:toRect];
[aLayer addAnimation:a forKey:@"boundsAnimation"];
NSLog(@”bounds:%@”, NSStringFromCGRect(aLayer.bounds));
• 還是會看到原本的 bounds,而不是動畫的 toValue 喔。
• 也就是說,在 layer 執行動畫的時候,去查看 layer 的 property,往往會跟你目前看到的不一樣。
Monday, March 28, 2011
我的 Layer 要跑好幾段動畫,怎樣
一個動畫做完再做一個動畫
?
Monday, March 28, 2011
一個動畫做完再做一個動畫
• [aLayer addAnimation:myAnimation1 forKey:@"MyKey1"];
• [aLayer addAnimation:myAnimation2 forKey:@"MyKey2"];
• 這兩個動畫會同時發生,不是一個跑完才跑下一個
Monday, March 28, 2011
話說你要這樣寫也是可以啦…
• [self performSelector:@selector(runAnimation1) withObject:nil afterDelay:1.0]; // 一秒
• [self performSelector:@selector(runAnimation2) withObject:nil afterDelay:2.0]; // 二秒
• 很醜,完全不建議
Monday, March 28, 2011
方法一:設定 beginTime
• animation1.beginTime = CACurrentMediaTime() + 1.0; // 一秒
• animation2.beginTime = CACurrentMediaTime() + 2.0; // 二秒
• 但有時候 CAAnimation 會被卡住,然後就被一起觸發,這樣不好…
Monday, March 28, 2011
什麼時候 animation 會被卡住?
• layer 所在的 view 不在最上面
• 已經先寫了動畫,才去產生用來放置 layer 的 UIView,再把 layer 放進 view.layer 裡
• app 在背景
• runloop 有東西卡住
• 總之,真的很常發生
Monday, March 28, 2011
方法二:用 delegate
animation.delegate = self;[myLayer addAnimation: animation forKey:@”key”];...- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {// Fire another animation} // 這樣才會確實在第一個動畫結束時跑另一個動畫
Monday, March 28, 2011
delegate 如何辨識是哪個 animation?…有點鳥蛋animation.delegate = self;animation.removedOnCompletion = NO;[myLayer addAnimation: animation forKey:@”key”];
...
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {if (theAnimation == [myLayer animationForKey:@”key”]) {
// Fire another animation [myLayer removeAllAnimations];
}}
// 目前還沒想到更好的辦法
Monday, March 28, 2011
λ 抱怨 λ
• 一個 CAAnimation 結束的時候應該要有 block 可以跑啊啊啊啊啊啊啊…
• iOS 5 會有嗎?
• Lion 好像還沒看到
Monday, March 28, 2011
一些撇步
Monday, March 28, 2011
自動排列 CALayer?
• UILayer -layoutSublayers
• 我也常用 UIView -layoutSubviews 就是了…
Monday, March 28, 2011
不設定 contents,而是在 CALayer 中用 Quartz 畫圖
- (void)drawInContext:(CGContextRef)ctx{ UIGraphicsPushContext(ctx);
// 把 ctx 變成 current graphics context 來用 :D UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:10.0]; CGContextSaveGState(ctx); CGContextAddPath(ctx, path.CGPath); CGContextClip(ctx); [image drawInRect:self.bounds]; CGContextRestoreGState(ctx); UIGraphicsPopContext();}
Monday, March 28, 2011
透過某個 view 的 layer 取得這個 view 畫面
UIGraphicsBeginImageContext(self.bounds.size);CGContextRef ctx = UIGraphicsGetCurrentContext();[self.layer renderInContext:ctx];UIImage *anImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext(); return anImage;
// 這個很好用 :D
Monday, March 28, 2011
最後
Monday, March 28, 2011
在 Mac 上面,不要在用到 Cocoa Drawing 的 NSView 中加上 CALayer,不要混用…
因為會慢到爆
Monday, March 28, 2011
別忘了 Accessibility
• 讓視障朋友也可以順利使用 app
• 不過大部分人好像都不太注意…
• 一般的 UIView/UIControl 都支援 Accessibility,但是如果拿 CALayer 做成按鈕,需要自己實作 Accessibility 支援
• 不過今天也沒時間細說…
Monday, March 28, 2011
完了Das ist alles.
Monday, March 28, 2011