一、CALayer常用屬性:
屬性 | 說明 | 是否支持隱式動畫 |
---|---|---|
anchorPoint | 和中心點position重合的一個點,稱爲“錨點”,錨點的描述是相對於x、y位置比例而言的默認在圖像中心點(0.5,0.5)的位置 | 是 |
backgroundColor | 圖層背景顏色 | 是 |
borderColor | 邊框顏色 | 是 |
borderWidth | 邊框寬度 | 是 |
bounds | 圖層大小 | 是 |
contents | 圖層顯示內容,例如可以將圖片作爲圖層內容顯示 | 是 |
contentsRect | 圖層顯示內容的大小和位置 | 是 |
cornerRadius | 圓角半徑 | 是 |
doubleSided | 圖層背面是否顯示,默認爲YES | 否 |
frame | 圖層大小和位置,不支持隱式動畫,所以CALayer中很少使用frame,通常使用bounds和position代替 | 否 |
hidden | 是否隱藏 | 是 |
mask | 圖層蒙版 | 是 |
maskToBounds | 子圖層是否剪切圖層邊界,默認爲NO | 是 |
opacity | 透明度 ,類似於UIView的alpha | 是 |
position | 圖層中心點位置,類似於UIView的center | 是 |
shadowColor | 陰影顏色 | 是 |
shadowOffset | 陰影偏移量 | 是 |
shadowOpacity | 陰影透明度,注意默認爲0,如果設置陰影必須設置此屬性 | 是 |
shadowPath | 陰影的形狀 | 是 |
shadowRadius | 陰影模糊半徑 | 是 |
sublayers | 子圖層 | 是 |
sublayerTransform | 子圖層形變 | 是 |
transform | 圖層形變 | 是 |
- 在CALayer中很少使用frame屬性,因爲frame本身不支持動畫效果,通常使用bounds和position代替。
- CALayer中透明度使用opacity表示而不是alpha;中心點使用position表示而不是center。
- MasksToBounds=YES之後,陰影不起作用,可以在其下面再添加一層陰影圖層,實現圓角加陰影效果。
-
CAAnimation和CALayer是鍵值編碼適應的容器類,容器類的意思是你可以爲任意的鍵設置值。即使有些鍵在CALayer中沒有聲明,你仍然可以像下面一樣設置值:
[theLayer setValue:@50 forKey:@”someKey”];
你可以像檢索其他鍵路徑一樣檢索任意鍵的值。比如爲了檢索之前設置的someKey鍵的值,可以像下面代碼一樣操作:
someKeyValue = [theLayer valueForKey:@”someKey”];
CAAnimation:核心動畫的基礎類,不能直接使用,負責動畫運行時間、速度的控制,本身實現了CAMediaTiming協議。
CAPropertyAnimation:屬性動畫的基類(通過屬性進行動畫設置,注意是可動畫屬性),不能直接使用。
CAAnimationGroup:動畫組,動畫組是一種組合模式設計,可以通過動畫組來進行所有動畫行爲的統一控制,組中所有動畫效果可以併發執行。
CATransition:轉場動畫,主要通過濾鏡進行動畫效果設置。
CABasicAnimation:基礎動畫,通過屬性修改進行動畫參數控制,只有初始狀態和結束狀態。
CAKeyframeAnimation:關鍵幀動畫,同樣是通過屬性進行動畫參數控制,但是同基礎動畫不同的是它可以有多個狀態控制。
(1)、CABasicAnimation:CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"position"];
basicAnimation.delegate=self;
[basicAnimation setValue:[NSValue valueWithCGPoint:location] forKey:@"endLocation"];
//支持鍵值編碼
basicAnimation.fromValue=[NSValue valueWithCGPoint:_layer.position];
basicAnimation.toValue=[NSValue valueWithCGPoint:location];
basicAnimation.duration=.3;
// basicAnimation.removedOnCompletion=FALSE;
// basicAnimation.fillMode=kCAFillModeBoth;
// fillMode的作用就是決定當前對象過了非active時間段的行爲. 比如動畫開始之前,動畫結束之後。如果是一個動畫CAAnimation,則需要將其removedOnCompletion設置爲NO,要不然fillMode不起作用.
// kCAFillModeRemoved 這個是默認值,也就是說當動畫開始前和動畫結束後,動畫對layer都沒有影響,動畫結束後,layer會恢復到之前的狀態
// kCAFillModeForwards 當動畫結束後,layer會一直保持着動畫最後的狀態
// kCAFillModeBackwards 這個和kCAFillModeForwards是相對的,就是在動畫開始前,你只要將動畫加入了一個layer,layer便立即進入動畫的初始狀態並等待動畫開始.你可以這樣設定測試代碼,將一個動畫加入一個layer的時候延遲5秒執行.然後就會發現在動畫沒有開始的時候,只要動畫被加入了layer,layer便處於動畫初始狀態
// kCAFillModeBoth 理解了上面兩個,這個就很好理解了,這個其實就是上面兩個的合成.動畫加入後開始之前,layer便處於動畫初始狀態,動畫結束後layer保持動畫最後的狀態.
[_layer addAnimation:basicAnimation forKey:@"positionAnimation"];
關於動畫keyPath:
transform.scale =比例轉換
transform.scale.x =闊的比例轉換
transform.scale.y =高的比例轉換
transform.rotation.z =平面圖的旋轉
opacity =透明度
margin、zPosition、backgroundColor、cornerRadius、borderWidth、bounds、contents、contentsRect、cornerRadius、frame、hidden、mask、masksToBounds、opacity、position、shadowColor、shadowOffset、shadowOpacity、shadowRadius、
(2)、CAKeyframeAnimation:
關鍵幀分兩種類型://第一種方式:關鍵值
CAKeyframeAnimation *keyframeAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"];
NSArray *values=@[[NSValue valueWithCGPoint:_layer.position],
[NSValue valueWithCGPoint:CGPointMake(150, 140)],
[NSValue valueWithCGPoint:CGPointMake(120, 160)],
[NSValue valueWithCGPoint:CGPointMake(150, 200)],
[NSValue valueWithCGPoint:location]];
keyframeAnimation.values=values;
NSArray *times=@[[NSNumber numberWithFloat:.0],
[NSNumber numberWithFloat:.3],
[NSNumber numberWithFloat:.6],
[NSNumber numberWithFloat:.8],
[NSNumber numberWithFloat:1.0]];
keyframeAnimation.keyTimes=times;
keyframeAnimation.duration=4.0;
[_layer addAnimation:keyframeAnimation forKey:@"keyAnimation"];</span>
//第二種方式:關鍵路徑
CAKeyframeAnimation *keyframeAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"];
CGMutablePathRef pathRef = CGPathCreateMutable();
CGPathMoveToPoint(pathRef, NULL, _layer.position.x, _layer.position.y);
CGPathAddCurveToPoint(pathRef, NULL, 100, 300, 250, 300, 175, 480);
keyframeAnimation.path=pathRef;
NSArray *times=@[[NSNumber numberWithFloat:.0],
[NSNumber numberWithFloat:.3],
[NSNumber numberWithFloat:.6],
[NSNumber numberWithFloat:.8],
[NSNumber numberWithFloat:1.0]];
keyframeAnimation.keyTimes=times;
keyframeAnimation.duration=4.0;
keyframeAnimation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
/** Timing function names. **/
/*
CA_EXTERN NSString * const kCAMediaTimingFunctionLinear //直線勻速
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAMediaTimingFunctionEaseIn //減速
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAMediaTimingFunctionEaseOut //加速
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAMediaTimingFunctionEaseInEaseOut //先減速再加速
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAMediaTimingFunctionDefault //默認
__OSX_AVAILABLE_STARTING (__MAC_10_6, __IPHONE_3_0);
*/
// keyframeAnimation.calculationMode=kCAAnimationDiscrete;
/*
CA_EXTERN NSString * const kCAAnimationLinear
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAAnimationDiscrete
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAAnimationPaced
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAAnimationCubic
__OSX_AVAILABLE_STARTING (__MAC_10_7, __IPHONE_4_0);
CA_EXTERN NSString * const kCAAnimationCubicPaced
__OSX_AVAILABLE_STARTING (__MAC_10_7, __IPHONE_4_0);
*/
[_layer addAnimation:keyframeAnimation forKey:@"keyAnimation"];
(3)、CAAnimationGroup:
- (CABasicAnimation *)scaleAnimaion
{
CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.scale"];
basicAnimation.toValue=[NSValue valueWithCATransform3D:CATransform3DMakeScale(transformScale, transformScale, 1)];
return basicAnimation;
}
- (CABasicAnimation *)rotationAnimation
{
CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
basicAnimation.toValue=[NSNumber numberWithFloat:M_PI_2*3];
return basicAnimation;
}
- (void)groupAnimation
{
CABasicAnimation *scaleAnimation=[self scaleAnimaion];
CABasicAnimation *rotationAnimation=[self rotationAnimation];
CAAnimationGroup *groupAnimation=[CAAnimationGroup animation];
groupAnimation.animations=@[scaleAnimation,rotationAnimation];
groupAnimation.duration=animationTime;
groupAnimation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
groupAnimation.autoreverses=true;
groupAnimation.repeatCount=HUGE_VALF;
[_layer addAnimation:groupAnimation forKey:@"groupAnimation"];
_start=YES;
}
(4)、CATransition:
CATransition *transition =[[CATransition alloc]init];
transition.type=kCATransitionMoveIn;
//對於蘋果官方沒有公開的動畫類型,只能用字符串來表示,並沒有常量定義。// transition.type=@"cube"; transition.type=kCATransitionMoveIn ; transition.subtype=kCATransitionFromRight; [_imgView.layer addAnimation:transition forKey:@"Transition"];
動畫類型 | 說明 | 對應常量 | 是否支持方向設置 |
---|---|---|---|
公開API | |||
fade | 淡出效果 | kCATransitionFade | 是 |
movein | 新視圖移動到舊視圖上 | kCATransitionMoveIn | 是 |
push | 新視圖推出舊視圖 | kCATransitionPush | 是 |
reveal | 移開舊視圖顯示新視圖 | kCATransitionReveal | 是 |
私有API | 私有API只能通過字符串訪問 | ||
cube | 立方體翻轉效果 | 無 | 是 |
oglFlip | 翻轉效果 | 無 | 是 |
suckEffect | 收縮效果 | 無 | 否 |
rippleEffect | 水滴波紋效果 | 無 | 否 |
pageCurl | 向上翻頁效果 | 無 | 是 |
pageUnCurl | 向下翻頁效果 | 無 | 是 |
cameralIrisHollowOpen | 攝像頭打開效果 | 無 | 否 |
cameraIrisHollowClose | 攝像頭關閉效果 | 無 | 否 |
另外對於支持方向設置的動畫類型還包含子類型:
動畫子類型 | 說明 |
---|---|
kCATransitionFromRight | 從右側轉場 |
kCATransitionFromLeft | 從左側轉場 |
kCATransitionFromTop | 從頂部轉場 |
kCATransitionFromBottom | 從底部轉場 |
注:可以實現無限循環圖片瀏覽器。
三、動畫相關重點:
(1)、CATransaction :
區分隱式動畫和隱式事務:隱式動畫通過隱式事務實現動畫 。
區分顯式動畫和顯式事務:顯式動畫有多種實現方式,顯式事務是一種實現顯式動畫的方式。
除顯式事務外,任何對於CALayer屬性的修改,都是隱式事務.這樣的事務會在run-loop中被提交.
//設置變化動畫過程是否顯示,默認爲YES不顯示
[CATransaction setDisableActions:NO];
//設置圓角
layer.cornerRadius = (layer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
//設置透明度
layer.opacity = (layer.opacity == 1.0f) ? 0.5f : 1.0f;
顯示事務通過明確的調用begin,commit來提交動畫
[CATransaction begin];
[CATransaction begin];
[CATransaction setDisableActions:YES];
layer.cornerRadius = (layer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
[CATransaction commit];
//上面的動畫並不會立即執行,需要等最外層的commit
[NSThread sleepForTimeInterval:10];
//顯式事務默認開啓動畫效果,kCFBooleanTrue關閉
[CATransaction setValue:(id)kCFBooleanFalse
forKey:kCATransactionDisableActions];
//動畫執行時間
[CATransaction setValue:[NSNumber numberWithFloat:10.0f] forKey:kCATransactionAnimationDuration];
//[CATransaction setAnimationDuration:[NSNumber numberWithFloat:5.0f]];
anotherLayer.cornerRadius = (anotherLayer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
[CATransaction commit];
(2)、動畫暫停與繼續:
- (IBAction)continueAnimation:(id)sender {
if (_layer.speed==0) {
CFTimeInterval beginTime=CACurrentMediaTime()-_layer.timeOffset;
_layer.timeOffset=0;
_layer.beginTime=beginTime;
_layer.speed=1;
}
}
- (IBAction)pauseAnimation:(id)sender {
if (_layer.speed==1) {
_layer.timeOffset=[_layer convertTime:CACurrentMediaTime() fromLayer:nil];
_layer.speed=0;
}
}
(3)、動畫定時器:- (void)viewDidLoad {
[super viewDidLoad];
_index=0;
CADisplayLink *displayLink=[CADisplayLink displayLinkWithTarget:self selector:@selector(bgColorChange:)];
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
// Do any additional setup after loading the view.
}
-(void)bgColorChange:(CADisplayLink *)displayLink
{
_index++;
if (_index==400) {
[displayLink invalidate];
}
int value_r=arc4random()%255;
int value_g=arc4random()%255;
int value_b=arc4random()%255;
self.view.backgroundColor=[UIColor colorWithRed:value_r/255.0 green:value_g/255.0 blue:value_b/255.0 alpha:1];
}
(4)、drawRect:與drawLayer:inContext、drawInContext:
KCALayer.m文件
#import "KCALayer.h"
@implementation KCALayer
- (void)drawInContext:(CGContextRef)ctx
{
NSLog(@"3-drawInContext:");
NSLog(@"CGContext:%@",ctx);
}
@end
KCView.m文件
#import "KCView.h"
#import "KCALayer.h"
@implementation KCView
- (instancetype)initWithFrame:(CGRect)frame
{
if (self=[super initWithFrame:frame]) {
KCALayer *layer=[[KCALayer alloc]init];
layer.bounds=CGRectMake(0, 0, 185, 185);
layer.position=CGPointMake(160, 284);
layer.backgroundColor=[UIColor colorWithRed:0 green:146/255.0 blue:1.0 alpha:1.0].CGColor;
[layer setNeedsDisplay];
[self.layer addSublayer:layer];
}
return self;
}
-(void)drawRect:(CGRect)rect{
NSLog(@"2-drawRect:");
NSLog(@"CGContext:%@",UIGraphicsGetCurrentContext());//得到的當前圖形上下文正是drawLayer中傳遞的
[super drawRect:rect];
}
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
NSLog(@"1-drawLayer:inContext:"); NSLog(@"CGContext:%@",ctx);[super drawLayer:layer inContext:ctx];
@end
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
// NSLog(@"%@",layer);//這個圖層正是上面定義的圖層
UIImage *image=[UIImage imageNamed:@"touxiang.jpg"];
//注意這個位置是相對於圖層而言的不是屏幕
CGContextDrawImage(ctx, CGRectMake(0, 0, PHOTO_HEIGHT, PHOTO_HEIGHT), image.CGImage);
}
layer.contents = (id)[UIImage imageNamed:@"view_BG.png"].CGImage; // 給圖層添加背景圖片
drawInContext