CALayer簡介
CALayer主要是展示內(nèi)容和動(dòng)畫操作,CALayer不包含在UIKit中,不能響應(yīng)事件,由于CALayer在設(shè)計(jì)之初就考慮它的動(dòng)畫操作功能,CALayer很多屬性在修改時(shí)都能形成動(dòng)畫效果,這種屬性稱為“隱式動(dòng)畫屬性”。對于UIView的根圖層而言屬性的修改并不形成動(dòng)畫效果,因?yàn)楹芏嗲闆r下根圖層更多的充當(dāng)容器的做用,如果它的屬性變動(dòng)形成動(dòng)畫效果會(huì)直接影響子圖層。另外,UIView的根圖層創(chuàng)建工作完全由iOS負(fù)責(zé)完成,無法重新創(chuàng)建,但是可以往根圖層中添加子圖層或移除子圖層。
CALayer屬性:
屬性 | 說明 | 是否支持隱式動(dòng)畫 |
---|---|---|
anchorPoint | 和中心點(diǎn)position重合的一個(gè)點(diǎn),稱為“錨點(diǎn)”,錨點(diǎn)的描述是相對于x、y位置比例而言的默認(rèn)在圖像中心點(diǎn)(0.5,0.5)的位置 | 是 |
backgroundColor | 圖層背景顏色 | 是 |
borderColor | 邊框顏色 | 是 |
borderWidth | 邊框?qū)挾?/td> | 是 |
bounds | 圖層大小 | 是 |
contents | 圖層顯示內(nèi)容,例如可以將圖片作為圖層內(nèi)容顯示 | 是 |
contentsRect | 圖層顯示內(nèi)容的大小和位置 | 是 |
cornerRadius | 圓角半徑 | 是 |
doubleSided | 圖層背面是否顯示,默認(rèn)為YES | 否 |
frame | 圖層大小和位置,不支持隱式動(dòng)畫,所以CALayer中很少使用frame,通常使用bounds和position代替 | 否 |
hidden | 是否隱藏 | 是 |
mask | 圖層蒙版 | 是 |
maskToBounds | 子圖層是否剪切圖層邊界,默認(rèn)為NO | 是 |
opacity | 透明度 ,類似于UIView的alpha | 是 |
position | 圖層中心點(diǎn)位置,類似于UIView的center | 是 |
shadowColor | 陰影顏色 | 是 |
shadowOffset | 陰影偏移量 | 是 |
shadowOpacity | 陰影透明度,注意默認(rèn)為0,如果設(shè)置陰影必須設(shè)置此屬性 | 是 |
shadowPath | 陰影的形狀 | 是 |
shadowRadius | 陰影模糊半徑 | 是 |
sublayers | 子圖層 | 是 |
sublayerTransform | 子圖層形變 | 是 |
transform | 圖層形變 | 是 |
-CALayer中透明度使用opacity而不是我們平常使用的alpha,中心點(diǎn)使用position而不是center </br>
-CALayer中很少使用frame屬性,frame屬性不支持動(dòng)畫,可以用bounds、position代替 </br>
-anchorPoint圖層的錨點(diǎn),范圍在(01,01)表示在x、y軸的比例,這個(gè)點(diǎn)永遠(yuǎn)可以同position(中心點(diǎn))重合,當(dāng)圖層中心點(diǎn)固定后,調(diào)整anchorPoint即可達(dá)到調(diào)整圖層顯示位置的作用(因?yàn)樗肋h(yuǎn)和position重合)</br>
CALayer繪圖
UIView中drawRect方法繪制圖形、圖像,本質(zhì)是在圖層中繪制。而這里介紹如何直接在圖層中繪制。在圖層中繪圖基本沒有什么區(qū)別,只是drawRect方法是由UIKit組件進(jìn)行調(diào)用,因此可以調(diào)用一些UIKit封裝的方法進(jìn)行繪圖,而直接繪制到圖層的方法只能用原生的Core Graphics方法繪制。
圖層繪圖有兩種方法,不管使用哪種方法都要調(diào)用setNeedsDisplay(UIView和CALayer都有setNeedsDisplay方法, 而這里調(diào)用的是圖層的方法)</br>
1、定義圖層繪制
// 繼承CALayer 實(shí)現(xiàn)方法
- (void)drawInContext:(CGContextRef)ctx {
}
2、圖層代理繪制
// CALayerDelegate 代理方法
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
}
使用定義圖層繪制
在自定義圖層時(shí),需要繼承CALayer創(chuàng)建文件,在.m文件中實(shí)現(xiàn)-(void)drawInContext:(CGContextRef)ctx {},顯示圖層中繪制的內(nèi)容也要調(diào)用圖層的setNeedDisplay方法,否則drawInContext方法將不會(huì)調(diào)用。
#import "MyCALayer.h"
#import <UIKit/UIKit.h>
@implementation MyCALayer
- (void)drawInContext:(CGContextRef)ctx {
CGContextSaveGState(ctx);
//圖形上下文形變,解決圖片倒立的問題
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -100);
UIImage *image = [UIImage imageNamed:@"vehicleResource.png"];
//注意這個(gè)位置是相對于圖層而言的不是屏幕
CGContextDrawImage(ctx, CGRectMake(0, 0, 100, 100), image.CGImage);
CGContextRestoreGState(ctx);
}
@end
#import "ViewController.h"
#import "MyCALayer.h"
@interface ViewController ()
@property (nonatomic, strong) MyCALayer *myCALayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIView *showView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
self.myCALayer = [[MyCALayer alloc] init];
self.myCALayer.bounds = CGRectMake(0, 0, 100, 100);
self.myCALayer.position = CGPointMake(50, 50);
[showView.layer addSublayer:self.myCALayer];
showView.backgroundColor = [UIColor redColor];
[self.view addSubview:showView];
[self.myCALayer setNeedsDisplay];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
使用圖層代理繪制
首先設(shè)置圖層代理,實(shí)現(xiàn)代理協(xié)議方法- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx,設(shè)置完代理后必須要調(diào)用圖層的setNeedDisplay方法,否則繪制的內(nèi)容無法顯示。
#import "ViewController.h"
@interface ViewController () <CALayerDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIView *showView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
// 設(shè)置背景
showView.layer.backgroundColor = [UIColor redColor].CGColor;
//注意僅僅設(shè)置圓角,對于圖形而言可以正常顯示,但是對于圖層中繪制的圖片無法正確顯示
//如果想要正確顯示則必須設(shè)置masksToBounds=YES,剪切子圖層
showView.layer.cornerRadius = 50;
showView.layer.masksToBounds = YES;
//陰影效果無法和masksToBounds同時(shí)使用,因?yàn)閙asksToBounds的目的就是剪切外邊框,
//設(shè)置陰影 顏色 偏移量 透明度
// showView.layer.shadowColor = [UIColor grayColor].CGColor;
// showView.layer.shadowOffset = CGSizeMake(2, 2);
// showView.layer.shadowOpacity = 1;
//設(shè)置邊框 顏色 寬度
showView.layer.borderColor = [UIColor whiteColor].CGColor;
showView.layer.borderWidth = 2;
//設(shè)置圖層代理
showView.layer.delegate = self;
[self.view addSubview:showView];
#warning 必須調(diào)用 不然無法繪制
[showView.layer setNeedsDisplay];
}
/**
繪制圖形、圖像到圖層,注意參數(shù)中的ctx是圖層的圖形上下文,其中繪圖位置也是相對圖層而言的
@param layer 圖層
@param ctx 圖形上下文
*/
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
CGContextSaveGState(ctx);
//圖形上下文形變,解決圖片倒立的問題
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -100);
UIImage *image = [UIImage imageNamed:@"vehicleResource.png"];
//注意這個(gè)位置是相對于圖層而言的不是屏幕
CGContextDrawImage(ctx, CGRectMake(0, 0, 100, 100), image.CGImage);
CGContextRestoreGState(ctx);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
使用代理方法繪制圖形、圖像時(shí),通過- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx方法獲取圖形上下文,圖形上下文指的當(dāng)前圖層的上下文,繪圖中的位置是相對于當(dāng)前圖層而言的。
在上述代碼中masksToBounds不設(shè)置是無法顯示圓形效果,但是對于其他圖形沒有這個(gè)限制,是因?yàn)槔L制一張圖片到圖層上的時(shí)候會(huì)重新創(chuàng)建一個(gè)圖層添加到當(dāng)前圖層,設(shè)置圓角的圖層是底圖層,子圖層還是矩形,只有設(shè)置了masksToBounds為YES讓子圖層按底圖層剪切才能顯示圓角效果。
如果我們同時(shí)需要圓形圖像又要陰影效果,我們只需要在添加一個(gè)圖層就能完美解決,只要把陰影圖層放在繪制圖形的下一層就好。我們在使用Core Graphics繪制圖片時(shí)會(huì)倒立顯示,對圖層的圖形上下文進(jìn)行了反轉(zhuǎn)。其實(shí)可以控制圖層直接旋轉(zhuǎn)而不用借助于圖形上下文的形變操作,只需要設(shè)置圖層的transform屬性即可。需要注意的是transform是CATransform3D類型,形變可以在三個(gè)維度上進(jìn)行。
形變對于動(dòng)畫有特殊的意義。在動(dòng)畫開發(fā)中形變往往不是直接設(shè)置transform,而是通過keyPath進(jìn)行設(shè)置。這種方法設(shè)置形變的本質(zhì)和前面沒有區(qū)別,只是利用了KVC可以動(dòng)態(tài)修改其屬性值而已,但是這種方式在動(dòng)畫中確實(shí)很常用的,因?yàn)樗梢院芊奖愕膶追N形變組合到一起使用。同樣是解決動(dòng)畫旋轉(zhuǎn)問題,只要將前面的旋轉(zhuǎn)代碼改為下面的代碼即可:
[layer setValue:@M_PI forKeyPath:@"transform.rotation.x"];
當(dāng)然,通過key path設(shè)置形變參數(shù)就需要了解有哪些key path可以設(shè)置.