1. CALayer和UIView之間的關系:
- 在iOS系統中,你能看得見摸得着的東西基本上都是UIView,比如UI控件、圖標等等,都是UIView。
- 其實UIView之所以能顯示在屏幕上,完全是因為它內部的一個層(CALayer)。
- 在創建UIView對象時,UIView內部會自動創建一個層(即CALayer對象),通過UIView的layer屬性可以訪問這個層。當UIView需要顯示到屏幕上時,會調用drawRect:方法進行繪圖,並且會將所有內容繪制在自己的層上,繪圖完畢后,系統會將層拷貝到屏幕上,於是就完成了UIView的顯示。
- 換句話說,UIView本身不具備顯示的功能,是它內部的層才有顯示功能。
- UIView之所以能夠顯示,完全是因為內部的CALayer對象。因此,通過操作這個CALayer對象,可以很方便地調整UIView的一些界面屬性,比如:陰影、圓角大小、邊框寬度和顏色等。
設置圖片的圓角和旋轉:
1 UIImageView *im = [[UIImageView alloc]init]; 2 im.frame = CGRectMake(100, 100, 100, 100); 3 im.image = [UIImage imageNamed:@"收藏背景"]; 4 im.layer.cornerRadius = 10; 5 im.layer.masksToBounds = YES; 6 im.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1); 7 [self.view addSubview:im];
2.UIView可以通過addSubview:方法添加子視圖,類似地,CALayer可以通過addSublayer:方法添加子層
1 CALayer *myLayer = [CALayer layer]; 2 // 設置層的寬度和高度(100x100)
3 myLayer.bounds = CGRectMake(0, 0, 100, 100); 4 // 設置層的位置
5 myLayer.position = CGPointMake(200, 100); 6 // 設置需要顯示的圖片
7 myLayer.contents = (id)[UIImage imageNamed:@"0000.png"].CGImage; 8 // 設置層的圓角半徑為10
9 myLayer.cornerRadius = 10; 10 // 如果設置了圖片,需要設置這個屬性為YES才有圓角效果
11 myLayer.masksToBounds = YES; 12
13 // 添加myLayer到控制器的view的layer中
14 [self.view.layer addSublayer:myLayer];
補充:CGImage是一種CGImageRef類型的數據
比如處理圖片只顯示某部分的時候,就用到了CGImageRef
1 UIImage *ima = [UIImage imageNamed:@"收藏背景"]; 2 // 圖片中需要顯示的部分
3 CGRect rect = CGRectMake(50, 50, 70, 70); 4 // 獲得顯示部分的數據
5 CGImageRef imageref = CGImageCreateWithImageInRect([ima CGImage], rect); 6 // 將數據轉化為圖片
7 UIImage *subimage = [UIImage imageWithCGImage:imageref]; 8 UIImageView *imageview = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)]; 9 imageview.image = subimage; 10 [self.view addSubview:imageview];
3.為什么CALayer中使用CGColorRef和CGImageRef這2種數據類型,而不用UIColor和UIImage?
* 首先要知道:CALayer是定義在QuartzCore框架中的;CGImageRef、CGColorRef兩種數據類型是定義在CoreGraphics框架中的;UIColor、UIImage是定義在UIKit框架中的
* 其次,QuartzCore框架和CoreGraphics框架是可以跨平台使用的,在iOS和Mac OS X上都能使用,但是UIKit只能在iOS中使用
* 因此,為了保證可移植性,QuartzCore不能使用UIImage、UIColor,只能使用CGImageRef、CGColorRef
* 不過很多情況下,可以通過UIKit對象的特定方法,得到CoreGraphics對象,比如UIImage的CGImage方法可以返回一個CGImageRef
4.如何選擇UIView和CALayer?
UIView相對於CALayer來說就是多一個事件處理的功能,CALayer是不能處理用戶的觸摸事件。故如果顯示出來的東西需要跟用戶進行交互的話,用UIView;如果不需要跟用戶進行交互,用UIView或者CALayer都可以。
5.其實UIView的顯示過程
當UIView需要顯示時,它內部的層會准備好一個CGContextRef(圖形上下文),然后調用delegate(這里就是UIView)的drawLayer:inContext:方法,並且傳入已經准備好的CGContextRef對象。而UIView在drawLayer:inContext:方法中又會調用自己的drawRect:方法
在drawRect:中通過UIGraphicsGetCurrentContext()獲取的就是由層傳入的CGContextRef對象,在drawRect:中完成的所有繪圖都會填入層的CGContextRef中,然后被拷貝至屏幕
6.自定義層
a.新建一個繼承於CALayer的類AACALayer,然后覆蓋drawInContext:方法,在里面繪圖
1 -(void)drawInContext:(CGContextRef)ctx{
3 CGContextSetRGBFillColor(ctx, 0, 1, 0.5, 1);//填充,出現實心
5 // 起點
7 CGContextMoveToPoint(ctx, 50, 0);
9 // 從(50, 0)連線到(0, 100)
11 CGContextAddLines(ctx, 0, 100);
13 // 從(0, 100)連線到(100, 100)
15 CGContextAddLineToPoint(ctx, 100, 100);
17 // 繪制路徑
19 CGContextClosePath(ctx); 20
21 }
則每次創建AACALayer,都會繪制一個三角形
1 AALayer *layer = [AALayer layer]; 2 // 設置層的寬高
3 layer.bounds = CGRectMake(0, 0, 100, 100); 4 // 設置層的位置
5 layer.position = CGPointMake(100, 100); 6 // 開始繪制圖層
7 [layer setNeedsDisplay];//寫這個方法才會自動觸發 drawInContext:的方法
8 [self.view.layer addSublayer:layer];
b.不想寫子類,也可以直接使用代理可以新建層,drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx中繪圖,但是不能將UIView設置為它的代理,否則和UIView內部就沖突了,因為UIView已經是內部根圖層的degegate了。
1 CALayer *layerr = [CALayer layer]; 2 // 設置層的寬高
3 layerr.bounds = CGRectMake(0, 0, 100, 100); 4 // 設置層的位置
5 layerr.position = CGPointMake(100, 100); 6 laere.delegate - self; 7 // 開始繪制圖層
8 [layer setNeedsDisplay];//無論采取哪種方法來自定義層,都必須調用CALayer的setNeedsDisplay方法才能正常繪圖。
9 [self.view.layer addSublayer:layer]; 10
11 //在代理方法中
12 - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx { 13 // 設置顏色
14 CGContextSetRGBStrokeColor(ctx, 0, 0, 1, 1);//這不填充,空心 15 // 設置邊框寬度
16 CGContextSetLineWidth(ctx, 5); 17
18 // 將矩形放到路徑中
19 CGContextAddRect(ctx, layer.bounds); 20
21 // 繪制路徑
22 CGContextStrokePath(ctx); 23 }
