轉(zhuǎn)載:http://www.reibang.com/p/18c306333080
CALayer在概念上和UIView類似胶惰,同樣也是一些被層級關(guān)系樹管理的矩形塊篓足,同樣也可以包含一些內(nèi)容(像圖片啼肩,文本或者背景色)忆首,管理子圖層的位置够话。并且它們有一些方法和屬性用來做動畫和變換担汤,但是CALayer不能響應(yīng)事件壤巷。
UIView是基于CALayer的一種封裝,每一個UIView都有一個CALayer實(shí)例的圖層屬性铭段,也就是所謂的backing layer骤宣,視圖的職責(zé)就是創(chuàng)建并管理這個圖層,以確保當(dāng)子視圖在層級關(guān)系中添加或者被移除的時候序愚,他們關(guān)聯(lián)的圖層也同樣對應(yīng)在層級關(guān)系樹當(dāng)中有相同的操作憔披。UIView的尺寸樣式以及內(nèi)容都由CALayer提供。
大多數(shù)情況下我們都使用UIView而不使用CALayer的原因是爸吮,首先是CALayer不能響應(yīng)事件芬膝,其次是CALayer不方便自動布局,最重要的是蘋果已經(jīng)基于CALayer封裝好了UIView拗胜,我們在使用UIView高級接口的同時也能使用CALayer的底層功能蔗候。
既然這里提到了層級樹,順便提一下事件響應(yīng)鏈:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event{
UIResponder* next = [selfnextResponder];
NSMutableString* prefix =@"-".mutableCopy;
while(next !=nil) {
? ? ? ? ? NSLog(@"%@%@", prefix, [nextclass]);? ?
? ? ? ? ? ?[prefix appendString:@"--"];? ? ?
? ? ? ? ? ?next = [next nextResponder];? }
}
2. CALayer內(nèi)容相關(guān)的屬性
contents
可以給CALayer的contents賦值
self.layerView.layer.contents= (__bridgeid)image.CGImage;
contentGravity
可以類似設(shè)置UIView的contentModel一樣埂软,設(shè)置CALayer的contentGravity
self.layerView.layer.contentsGravity = kCAGravityResizeAspect;
contentGravity可以賦值的常量值如下
CA_EXTERNNSString*constkCAGravityCenterCA_AVAILABLE_STARTING(10.5, 2.0, 9.0, 2.0);CA_EXTERNNSString*constkCAGravityTopCA_AVAILABLE_STARTING(10.5, 2.0, 9.0, 2.0);CA_EXTERNNSString*constkCAGravityBottomCA_AVAILABLE_STARTING(10.5, 2.0, 9.0, 2.0);CA_EXTERNNSString*constkCAGravityLeftCA_AVAILABLE_STARTING(10.5, 2.0, 9.0, 2.0);CA_EXTERNNSString*constkCAGravityRightCA_AVAILABLE_STARTING(10.5, 2.0, 9.0, 2.0);CA_EXTERNNSString*constkCAGravityTopLeftCA_AVAILABLE_STARTING(10.5, 2.0, 9.0, 2.0);CA_EXTERNNSString*constkCAGravityTopRightCA_AVAILABLE_STARTING(10.5, 2.0, 9.0, 2.0);CA_EXTERNNSString*constkCAGravityBottomLeftCA_AVAILABLE_STARTING(10.5, 2.0, 9.0, 2.0);CA_EXTERNNSString*constkCAGravityBottomRightCA_AVAILABLE_STARTING(10.5, 2.0, 9.0, 2.0);CA_EXTERNNSString*constkCAGravityResizeCA_AVAILABLE_STARTING(10.5, 2.0, 9.0, 2.0);CA_EXTERNNSString*constkCAGravityResizeAspectCA_AVAILABLE_STARTING(10.5, 2.0, 9.0, 2.0);CA_EXTERNNSString*constkCAGravityResizeAspectFillCA_AVAILABLE_STARTING(10.5, 2.0, 9.0, 2.0);
contentsScale
CALayer的contentsScale屬性可以用以適配retina屏幕锈遥,該屬性值默認(rèn)為1.0纫事,將會以每個點(diǎn)1個像素繪制圖片,如果設(shè)置為2.0所灸,則會以每個點(diǎn)2個像素繪制圖片丽惶,這就是我們熟知的Retina屏幕。
UIImage*image = [UIImageimageNamed:@"doll"];UIView*view = [[UIViewalloc] initWithFrame:self.view.bounds];view.layer.contents = (__bridgeid_Nullable)(image.CGImage);view.layer.contentsGravity = kCAGravityCenter;[self.view addSubview:view];
運(yùn)行結(jié)果:
6CC1E4E8-6490-4586-BFA6-B146EC440776.png
可以看到顯示出來的圖片有像素顆粒感爬立,在上面代碼的基礎(chǔ)上再加上一句
view.layer.contentsScale = [UIScreen mainScreen].scale;
運(yùn)行結(jié)果:
B01FE8E0-7E06-4BA3-A95D-99D1F5BFC1CD.png
maskToBounds
類似UIView的clipsToBounds钾唬,CALayer有一個屬性叫maskToBounds
self.layerView.layer.masksToBounds =YES;
contentsRect
CALayer的contentsRect屬性可以用于圖片拼合
舉個栗子,有如下圖片:
doll@2x.png
我們可以利用contentsRect屬性來分別單獨(dú)顯示三個娃娃:
#import"ViewController.h"@interfaceViewController()@property(weak,nonatomic)IBOutletUIView*leftTopImage;@property(weak,nonatomic)IBOutletUIView*rightTopImage;@property(weak,nonatomic)IBOutletUIView*leftBottomImage;@end@implementationViewController-(void)viewDidLoad {? ? ? [superviewDidLoad];UIImage*image = [UIImageimageNamed:@"doll"];self.leftTopImage.layer.contents = (__bridgeid_Nullable)(image.CGImage);self.leftTopImage.layer.contentsRect =CGRectMake(0.0f,0.0f,0.5f,0.5f);self.rightTopImage.layer.contents = (__bridgeid_Nullable)(image.CGImage);self.rightTopImage.layer.contentsRect =CGRectMake(0.5f,0.0f,0.5f,0.5f);self.leftBottomImage.layer.contents = (__bridgeid_Nullable)(image.CGImage);self.leftBottomImage.layer.contentsRect =CGRectMake(0.0f,0.5f,0.5f,0.5f);}@end
運(yùn)行結(jié)果:
0EE9992A-027F-43C4-84DB-F2127EC2BCEE.png
拼合不僅給app提供了一個整潔的載入方式侠驯,還有效地提高了載入性能(單張大圖比多張小圖載入地更快)抡秆,但是如果有手動安排的話,他們還是有一些不方便的吟策,如果你需要在一個已經(jīng)創(chuàng)建好的品和圖上做一些尺寸上的修改或者其他變動儒士,無疑是比較麻煩的。
Mac上有一些商業(yè)軟件可以為你自動拼合圖片檩坚,這些工具自動生成一個包含拼合后的坐標(biāo)的XML或者plist文件着撩,拼合圖片的使用大大簡化。這個文件可以和圖片一同載入匾委,并給每個拼合的圖層設(shè)置contentsRect拖叙,這樣開發(fā)者就不用手動寫代碼來擺放位置了。
contentsCenter
CALayer的另一個屬性contentsCenter赂乐,有點(diǎn)類似于UIImage里的-resizableImageWithCapInsets: 方法薯鳍,樓主淺薄,實(shí)在不懂如何描述沪猴,這里有篇文章講得很清楚:iOS: 關(guān)于CALayer的contentsCenter屬性
3. CALayer位置坐標(biāo)相關(guān)的屬性
對應(yīng)于UIView的frame辐啄、bounds、center运嗜,CALayer有frame、bounds悯舟、position担租,訪問UIView的這三個屬性,返回的其實(shí)就是CALayer對應(yīng)的這三個值抵怎。但是CALayer另外還有一個比較難于理解的屬性anchorPoint奋救。
anchorPoint
anchorPoint決定了CALayer的那個點(diǎn)處于position的位置,其作用效果如下圖:
3.3.jpeg
坐標(biāo)轉(zhuǎn)換
CALayer也有用于在不同坐標(biāo)系中轉(zhuǎn)換坐標(biāo)的函數(shù):
-(CGPoint)convertPoint:(CGPoint)p fromLayer:(nullableCALayer*)l;-(CGPoint)convertPoint:(CGPoint)p toLayer:(nullableCALayer*)l;-(CGRect)convertRect:(CGRect)r fromLayer:(nullableCALayer*)l;-(CGRect)convertRect:(CGRect)r toLayer:(nullableCALayer*)l;
zPosition
CALayer的zPosition屬性可以控制圖層的顯示順序反惕,Interface Build布局如下:
Paste_Image.png
修改zPosition:
#import"ViewController.h"@interfaceViewController()@property(weak,nonatomic)IBOutletUIView*blueView;@property(weak,nonatomic)IBOutletUIView*orangeView;@end@implementationViewController-(void)viewDidLoad {? [superviewDidLoad];self.blueView.layer.zPosition =1.0f;}@end
運(yùn)行結(jié)果:
Paste_Image.png
zPosition屬性雖然可以改變圖層的顯示順序尝艘,但是不能改變圖層在圖層樹中的順序
CALayer事件處理
CALayer并不關(guān)心任何響應(yīng)鏈?zhǔn)录圆荒苤苯犹幚碛|摸事件或者手勢姿染。但是它有一系列的方法幫你處理事件:-containsPoint:和-hitTest:背亥。
-containsPoint:接受一個在本圖層坐標(biāo)系下的CGPoint,如果這個點(diǎn)在圖層frame范圍內(nèi)就返回YES。舉個栗子:
#import"ViewController.h"@interfaceViewController()@property(weak,nonatomic)IBOutletUIView*whiteView;@property(weak,nonatomic)IBOutletUIView*orangeView;@end@implementationViewController-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event{UITouch*touch = touches.anyObject;CGPointoriginPoint = [touch locationInView:self.view];CGPointthePoint = [self.whiteView.layer convertPoint:originPoint fromLayer:self.view.layer];BOOLcontainsResult = [self.whiteView.layer containsPoint:thePoint];if(containsResult) {? ? ? thePoint = [self.orangeView.layer convertPoint:thePoint fromLayer:self.whiteView.layer];? ? ? containsResult = [self.orangeView.layer containsPoint:thePoint];UIAlertController*alert;if(containsResult) {? ? ? ? ? alert = [UIAlertControlleralertControllerWithTitle:nilmessage:@"inside orange layer"preferredStyle:UIAlertControllerStyleAlert];? ? ? }else{? ? ? ? ? alert = [UIAlertControlleralertControllerWithTitle:nilmessage:@"inside white layer"preferredStyle:UIAlertControllerStyleAlert];? ? ? }? ? ? [alert addAction:[UIAlertActionactionWithTitle:@"OK"style:UIAlertActionStyleCancelhandler:nil]];? ? ? [selfpresentViewController:alert animated:YEScompletion:nil];? }}@end
運(yùn)行結(jié)果:
Paste.gif
-hitTest:方法同樣接受一個CGPoint類型參數(shù)狡汉,而不是BOOL類型娄徊,它返回圖層本身,或者包含這個坐標(biāo)點(diǎn)的葉子節(jié)點(diǎn)圖層盾戴,如果這個點(diǎn)在最外面圖層的范圍之外寄锐,則返回nil。
下面這段代碼實(shí)現(xiàn)了上圖一樣的效果:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event{UITouch*touch = touches.anyObject;CGPointoriginPoint = [touch locationInView:self.view];CALayer*layer = [self.whiteView.layer hitTest:originPoint];UIAlertController*alert;if(layer ==self.orangeView.layer) {? ? ? alert = [UIAlertControlleralertControllerWithTitle:nilmessage:@"inside orange layer"preferredStyle:UIAlertControllerStyleAlert];? }else{? ? ? alert = [UIAlertControlleralertControllerWithTitle:nilmessage:@"inside white layer"preferredStyle:UIAlertControllerStyleAlert];? }? [alert addAction:[UIAlertActionactionWithTitle:@"OK"style:UIAlertActionStyleCancelhandler:nil]];? [selfpresentViewController:alert animated:YEScompletion:nil];}
4. CALayer視覺相關(guān)的屬性
conrnerRadius
CALayer有一個叫做conrnerRadius的屬性控制著圖層角的曲率尖啡。它是一個浮點(diǎn)數(shù)橄仆,默認(rèn)為0(為0的時候就是直角),但是你可以把它設(shè)置成任意值衅斩。默認(rèn)情況下沿癞,這個曲率值只影響背景顏色而不影響背景圖片或是子圖層。不過矛渴,如果把masksToBounds設(shè)置成YES的話椎扬,圖層里面的所有東西都會被截取。
Interface Build布局如下:
Paste_Image.png
添加如下代碼:
#import"ViewController.h"@interfaceViewController()@property(weak,nonatomic)IBOutletUIView*topWhiteView;@property(weak,nonatomic)IBOutletUIView*bottomWhiteView;@end@implementationViewController-(void)viewDidLoad {? [superviewDidLoad];// Do any additional setup after loading the view, typically from a nib.self.topWhiteView.layer.cornerRadius =20.0f;self.bottomWhiteView.layer.cornerRadius =20.0f;self.bottomWhiteView.layer.masksToBounds =YES;}@end
運(yùn)行效果:
Paste_Image.png
borderWidth和borderColor
CALayer另外兩個非常有用屬性就是borderWidth和borderColor具温。二者共同定義了圖層邊的繪制樣式蚕涤。這條線(也被稱作stroke)沿著圖層的bounds繪制,同時也包含圖層的角铣猩。在上面代碼的基礎(chǔ)上再加上幾句:
self.topWhiteView.layer.borderWidth=5.0f;self.bottomWhiteView.layer.borderWidth=5.0f;self.topWhiteView.layer.borderColor= [UIColor yellowColor].CGColor;self.bottomWhiteView.layer.borderColor= [UIColor yellowColor].CGColor;
運(yùn)行效果:
Paste_Image.png
陰影效果
CALayer還有一系列屬性用來繪制陰影:
/** Shadow properties. **//* The color of the shadow. Defaults to opaque black. Colors created
* from patterns are currently NOT supported. Animatable. */@property(nullable) CGColorRef shadowColor;/* The opacity of the shadow. Defaults to 0. Specifying a value outside the
* [0,1] range will give undefined results. Animatable. */@propertyfloat shadowOpacity;/* The shadow offset. Defaults to (0, -3). Animatable. */@propertyCGSize shadowOffset;/* The blur radius used to create the shadow. Defaults to 3. Animatable. */@propertyCGFloat shadowRadius;/* When non-null this path defines the outline used to construct the
* layer's shadow instead of using the layer's composited alpha
* channel. The path is rendered using the non-zero winding rule.
* Specifying the path explicitly using this property will usually
* improve rendering performance, as will sharing the same path
* reference across multiple layers. Upon assignment the path is copied.
* Defaults to null. Animatable. */@property(nullable) CGPathRef shadowPath;
在前面代碼的基礎(chǔ)上再加上幾句:
self.topWhiteView.layer.shadowColor= [UIColorblackColor].CGColor;self.bottomWhiteView.layer.shadowColor= [UIColorblackColor].CGColor;self.topWhiteView.layer.shadowOpacity=0.5f;self.bottomWhiteView.layer.shadowOpacity=0.5f;
運(yùn)行效果:
Paste_Image.png
發(fā)現(xiàn)兩個問題:
1揖铜、topWhiteView有陰影,但是陰影在視圖的上方
2达皿、而bottomWhiteView干脆根本沒有陰影
第一個問題的原因在于這個屬性:
/* The shadowoffset. Defaultsto(0,-3). Animatable. */@propertyCGSize shadowOffset;
CALayer的陰影偏移量默認(rèn)為(0, -3)天吓,所以陰影出現(xiàn)在了視圖的上方
第二個問題的原因在于這句代碼:
self.bottomWhiteView.layer.masksToBounds= YES;
如果你開啟了masksToBounds屬性,所有從圖層中突出來的內(nèi)容都會被才剪掉峦椰,一個簡單的解決辦法就是在bottomWhiteView的下面再插入一個view來充當(dāng)陰影視圖龄寞。
修改之前的代碼,最終代碼如下:
#import"ViewController.h"@interfaceViewController()@property(weak,nonatomic)IBOutletUIView*topWhiteView;@property(weak,nonatomic)IBOutletUIView*bottomWhiteView;@property(weak,nonatomic)IBOutletUIView*bottomBackView;@end@implementationViewController-(void)viewDidLoad {? [superviewDidLoad];// Do any additional setup after loading the view, typically from a nib.self.bottomWhiteView.layer.masksToBounds =YES;? [selfconfigLayer:self.topWhiteView.layer];? [selfconfigLayer:self.bottomWhiteView.layer];? [selfconfigLayer:self.bottomBackView.layer];}-(void)configLayer:(CALayer*)aLayer{? aLayer.cornerRadius =20.0f;//圓角aLayer.borderWidth =5.0f;//邊框線寬aLayer.borderColor = [UIColoryellowColor].CGColor;//邊框顏色aLayer.shadowColor = [UIColorblackColor].CGColor;//陰影顏色aLayer.shadowOpacity =0.5f;//陰影透明度aLayer.shadowOffset =CGSizeMake(5.0f,5.0f);//陰影偏移量}@end
運(yùn)行效果:
Paste_Image.png
shadowRadius
shadowRadius屬性可以控制CALayer陰影的模糊度汤功,在viewDidLoad方法的最后加上一句:
self.topWhiteView.layer.shadowRadius=10.0f;
運(yùn)行結(jié)果:
Paste_Image.png
shadowPath
shadowPath可以為CALayer指定特定的陰影路徑物邑。
舉個栗子:
#import"ViewController.h"@interfaceViewController()@property(weak,nonatomic)IBOutletUIView*orangeView;@property(weak,nonatomic)IBOutletUIView*cyanView;@end@implementationViewController-(void)viewDidLoad {? [superviewDidLoad];// Do any additional setup after loading the view, typically from a nib.[selfconfigLayer:self.orangeView.layer];? [selfconfigLayer:self.cyanView.layer];//create a square shadowCGMutablePathRefsquarePath =CGPathCreateMutable();CGPathAddRect(squarePath,NULL,self.cyanView.bounds);self.cyanView.layer.shadowPath = squarePath;CGPathRelease(squarePath);//create a circular shadowCGMutablePathRefcirclePath =CGPathCreateMutable();CGPathAddEllipseInRect(circlePath,NULL,self.orangeView.bounds);self.orangeView.layer.shadowPath = circlePath;CGPathRelease(circlePath);}-(void)configLayer:(CALayer*)aLayer{? aLayer.shadowOpacity =0.5f;? aLayer.cornerRadius = aLayer.bounds.size.width /2.0f;? aLayer.shadowOffset =CGSizeMake(0.0f,0.0f);? aLayer.shadowRadius =5.0f;}@end
運(yùn)行效果:
Paste_Image.png
mask
mask圖層定義了父圖層的部分可見區(qū)域,mask圖層的Color屬性是無關(guān)緊要的滔金,真正重要的是圖層的輪廓色解。mask屬性就像是一個餅干切割機(jī),mask圖層實(shí)心的部分會被保留下來餐茵,其他的則會被拋棄科阎。
舉個栗子:
Interface Build布局如下:
Paste_Image.png
使用下面這個小雪人來充當(dāng)圖層蒙版:
3.png
代碼如下:
#import"ViewController.h"@interfaceViewController()@property(weak,nonatomic)IBOutletUIImageView*imageView;@end@implementationViewController-(void)viewDidLoad {? [superviewDidLoad];// Do any additional setup after loading the view, typically from a nib.//create mask layerCALayer*maskLayer = [CALayerlayer];? maskLayer.frame =self.imageView.bounds;UIImage*maskImage = [UIImageimageNamed:@"3"];? maskLayer.contents = (__bridgeid)maskImage.CGImage;? maskLayer.contentsGravity = kCAGravityCenter;? maskLayer.contentsScale = [UIScreenmainScreen].scale;//apply mask to image layerself.imageView.layer.mask = maskLayer;}@end
運(yùn)行效果:
Paste_Image.png
每一個UIView內(nèi)部都默認(rèn)關(guān)聯(lián)著一個CALayer,我們可用稱這個Layer為Root Layer(根層)
所有的非Root Layer忿族,也就是手動創(chuàng)建的CALayer對象锣笨,都存在著隱式動畫
什么是隱式動畫蝌矛?
當(dāng)對非Root Layer的部分屬性進(jìn)行修改時,默認(rèn)會自動產(chǎn)生一些動畫效果
而這些屬性稱為Animatable Properties(可動畫屬性)
列舉幾個常見的Animatable Properties:
bounds:用于設(shè)置CALayer的寬度和高度票唆。修改這個屬性會產(chǎn)生縮放動畫
backgroundColor:用于設(shè)置CALayer的背景色朴读。修改這個屬性會產(chǎn)生背景色的漸變動畫
position:用于設(shè)置CALayer的位置。修改這個屬性會產(chǎn)生平移動畫
......
1.UIView可以通過subviews屬性訪問所有的子視圖走趋,類似地衅金,CALayer也可以通過sublayers屬性訪問所有的子層
2.UIView可以通過superview屬性訪問父視圖,類似地簿煌,CALayer也可以通過superlayer屬性訪問父層
3.特別注意:如果一個控件是另外一個控件的子控件氮唯,那么這個控件的layer也是另一個控件的子layer。
查看蘋果的官方文檔姨伟,下面的屬性都可以通過KVC進(jìn)行設(shè)置惩琉。
//
//? YYMylayer.m
//? 05-自定義layer(1)
//
//? Created by apple on 14-6-21.
//? Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYMylayer.h"
@implementation YYMylayer
//重寫該方法,在該方法內(nèi)繪制圖形
-(void)drawInContext:(CGContextRef)ctx
{
//1.繪制圖形
//畫一個圓
CGContextAddEllipseInRect(ctx, CGRectMake(50, 50, 100, 100));
//設(shè)置屬性(顏色)
//? ? [[UIColor yellowColor]set];
CGContextSetRGBFillColor(ctx, 0, 0, 1, 1);
//2.渲染
CGContextFillPath(ctx);
}
@en
//
//? YYViewController.m
//? 05-自定義layer(1)
//
//? Created by apple on 14-6-21.
//? Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYViewController.h"
#import "YYMylayer.h"
@interface YYViewController ()
@end
@implementation YYViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//1.創(chuàng)建自定義的layer
YYMylayer *layer=[YYMylayer layer];
//2.設(shè)置layer的屬性
layer.backgroundColor=[UIColor brownColor].CGColor;
layer.bounds=CGRectMake(0, 0, 200, 150);
layer.anchorPoint=CGPointZero;
layer.position=CGPointMake(100, 100);
layer.cornerRadius=20;
layer.shadowColor=[UIColor blackColor].CGColor;
layer.shadowOffset=CGSizeMake(10, 20);
layer.shadowOpacity=0.6;
[layer setNeedsDisplay];
//3.添加layer
[self.view.layer addSublayer:layer];
}
@end
注意點(diǎn):
(1)默認(rèn)為無色夺荒,不會顯示瞒渠。要想讓繪制的圖形顯示出來,還需要設(shè)置圖形的顏色技扼。注意不能直接使用UI框架中的類
(2)在自定義layer中的-(void)drawInContext:方法不會自己調(diào)用伍玖,只能自己通過setNeedDisplay方法調(diào)用,在view中畫東西DrawRect:方法在view第一次顯示的時候會自動調(diào)用剿吻。
實(shí)現(xiàn)效果:
#import "YYVIEW.h"
@implementation YYVIEW
- (void)drawRect:(CGRect)rect
{
//1.獲取上下文
CGContextRef ctx=UIGraphicsGetCurrentContext();
//2.繪制圖形
CGContextAddEllipseInRect(ctx, CGRectMake(50, 50, 100, 100));
//設(shè)置屬性(顏色)
//? ? [[UIColor yellowColor]set];
CGContextSetRGBFillColor(ctx, 0, 0, 1, 1);
//3.渲染
CGContextFillPath(ctx);
//在執(zhí)行渲染操作的時候窍箍,本質(zhì)上它的內(nèi)部相當(dāng)于調(diào)用了下面的方法
[self.layer drawInContext:ctx];
}
說明:在UIView中繪制圖形,獲取的上下文就是這個view對應(yīng)的layer的上下文丽旅。在渲染的時候椰棘,就是把圖形渲染到對應(yīng)的layer上。
在執(zhí)行渲染操作的時候榄笙,本質(zhì)上它的內(nèi)部相當(dāng)于執(zhí)行了?[self.layer drawInContext:ctx];
二邪狞、第二種方式
方法描述:設(shè)置CALayer的delegate,然后讓delegate實(shí)現(xiàn)drawLayer:inContext:方法办斑,當(dāng)CALayer需要繪圖時外恕,會調(diào)用delegate的drawLayer:inContext:方法進(jìn)行繪圖。
代碼示例:
//
//? YYViewController.m
//? 06-自定義layer(2)
//
//? Created by apple on 14-6-21.
//? Copyright (c) 2014年 itcase. All rights reserved.
#import "YYViewController.h"
@interface YYViewController ()
@end
@implementation YYViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//1.創(chuàng)建自定義的layer
CALayer *layer=[CALayer layer];
//2.設(shè)置layer的屬性
layer.backgroundColor=[UIColor brownColor].CGColor;
layer.bounds=CGRectMake(0, 0, 200, 150);
layer.anchorPoint=CGPointZero;
layer.position=CGPointMake(100, 100);
layer.cornerRadius=20;
layer.shadowColor=[UIColor blackColor].CGColor;
layer.shadowOffset=CGSizeMake(10, 20);
layer.shadowOpacity=0.6;
//設(shè)置代理
layer.delegate=self;
[layer setNeedsDisplay];
//3.添加layer
[self.view.layer addSublayer:layer];
}
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
//1.繪制圖形
//畫一個圓
CGContextAddEllipseInRect(ctx, CGRectMake(50, 50, 100, 100));
//設(shè)置屬性(顏色)
//? ? [[UIColor yellowColor]set];
CGContextSetRGBFillColor(ctx, 0, 0, 1, 1);
//2.渲染
CGContextFillPath(ctx);
}
@end
注意點(diǎn):不能再將某個UIView設(shè)置為CALayer的delegate乡翅,因?yàn)閁IView對象已經(jīng)是它內(nèi)部根層的delegate,再次設(shè)置為其他層的delegate就會出問題罪郊。
在設(shè)置代理的時候蠕蚜,它并不要求我們遵守協(xié)議,說明這個方法是nsobject中的悔橄,就不需要再額外的顯示遵守協(xié)議了靶累。
提示:以后如果要設(shè)置某個類的代理腺毫,但是這個代理沒要求我們遵守什么特定的協(xié)議,那么可以認(rèn)為這個協(xié)議方法是NSObject里邊的挣柬。
三潮酒、補(bǔ)充說明
(1)無論采取哪種方法來自定義層,都必須調(diào)用CALayer的setNeedsDisplay方法才能正常繪圖邪蛔。
(2)詳細(xì)現(xiàn)實(shí)過程:
當(dāng)UIView需要顯示時急黎,它內(nèi)部的層會準(zhǔn)備好一個CGContextRef(圖形上下文),然后調(diào)用delegate(這里就是UIView)的drawLayer:inContext:方法侧到,并且傳入已經(jīng)準(zhǔn)備好的CGContextRef對象勃教。而UIView在drawLayer:inContext:方法中又會調(diào)用自己的drawRect:方法。平時在drawRect:中通過UIGraphicsGetCurrentContext()獲取的就是由層傳入的CGContextRef對象匠抗,在drawRect:中完成的所有繪圖都會填入層的CGContextRef中故源,然后被拷貝至屏幕。