1、什么是CALayer?
? ? ? ?在創(chuàng)建UIView對象時,UIView內(nèi)部會自動創(chuàng)建一個層(即CALayer對象),通過UIView的layer屬性可以訪問這個層。當UIView需要顯示到屏幕上時,會調(diào)用drawRect:方法進行繪圖,并且會將所有內(nèi)容繪制在自己的層上,繪圖完畢后,系統(tǒng)會將層拷貝到屏幕上,于是就完成了UIView的顯示。
2、CALayer的簡單使用
? ? ? ? CALayer是被定義在QuartzCore框架中的,因此要想使用CALayer,先導入QuartzCore框架;在項目中導入QuartzCore頭文件。
使用場景:給控件設置陰影、設置圓角大小、設置邊框的顏色和寬度、設置旋轉?
? ? ? ?注意:這里使用UIColor的CGColor屬性。當設置了masksToBounds為YES時,將不再出現(xiàn)陰影效果
? ? ? ?另外:在設置圖片時.jpg格式的圖片在Assets文件之外無法使用imageNamed: 進行賦值
? ? ? UIView內(nèi)部默認有個CALayer對象(層),通過layer屬性可以訪問這個層。但是,這個默認的層不允許重新創(chuàng)建,可以往層里面添加子層。CALayer可以通過addSublayer:方法添加子層
Example :通過UIImageView進行舉例
UIImageView*img = [[UIImageViewalloc]initWithFrame:CGRectMake(100,100,200,200)];
img.image= [UIImageimageNamed:@"girl"];
[self.viewaddSubview:img];
// 1.設置陰影
img.layer.shadowColor= [UIColorgrayColor].CGColor;
img.layer.shadowOffset=CGSizeMake(10,10);
img.layer.shadowOpacity=0.5;
// 2.設置圓角
img.layer.cornerRadius=10;
img.layer.masksToBounds=YES;
// 3.設置邊框
img.layer.borderWidth=8;
img.layer.borderColor= [UIColoryellowColor].CGColor;
// 4.設置旋轉
img.layer.transform=CATransform3DMakeRotation(M_PI_4,0,0,1);
// 添加一個簡單的圖層
CALayer*layer = [CALayerlayer];
// 設置寬度和高度
layer.bounds=CGRectMake(0,0,100,100);
// 設置層的位置
layer.position=CGPointMake(100,400);
// 設置顏色
layer.backgroundColor= [UIColorblueColor].CGColor;
// 設置圓角
layer.cornerRadius=10;
// 設置邊框
layer.borderColor= [UIColorredColor].CGColor;
layer.borderWidth=8;
// 添加到父控件的layer上
[self.view.layeraddSublayer:layer];
// 添加一個現(xiàn)實圖片的圖層
CALayer*myLayer = [CALayerlayer];
myLayer.bounds=CGRectMake(0,0,100,100);
myLayer.position=CGPointMake(300,400);
// 設置需要顯示的圖片 注意:此刻是將圖片添加到contents的屬性上
myLayer.contents= (id)[UIImageimageNamed:@"girl"].CGImage;
myLayer.cornerRadius=10;
myLayer.masksToBounds=YES;
// 添加到父視圖的layer上
[self.view.layeraddSublayer:myLayer];
3、問題:為什么使用CGColorRef和CGImageRef這兩種數(shù)據(jù)類型?
? ? ? 首先,CALayer是定義在QuartzCore框架中的;CGImageRef、CGColorRef兩種數(shù)據(jù)類型是定義在CoreGraphics框架中的;UIColor、UIImage是定義在UIKit框架中的;其次,QuartzCore框架和CoreGraphics框架是可以跨平臺使用的,在iOS和Mac OS X上都能使用,但是UIKit只能在iOS中使用。因此,為了保證可移植性,QuartzCore不能使用UIImage、UIColor,只能使用CGImageRef、CGColorRef,比如實例中,我們可以通過UIKit對象的特定方法(CGImage),得到CoreGraphics對象
4、UIView和CALayer的區(qū)別:
1> UIView和CALayer最大的區(qū)別在于,UIView比CALayer多了一個處理事件的功能,也就是說CALayer不具備處理用戶觸摸事件的能力。所以可以通過判斷我們顯示的內(nèi)容是否需要和用戶進行交互確定采用何種方式來顯示
2> CALayer的性能會高一些,輕量級
5、隱式動畫屬性
? ? ? 每一個UIView內(nèi)部都默認關聯(lián)著一個CALayer,我們可用稱這個Layer為Root Layer(根層)。所有的非Root Layer,也就是手動創(chuàng)建的CALayer對象,都存在著隱式動畫。
? ? ? 當對非Root Layer的部分屬性進行相應的修改時,默認會自動產(chǎn)生一些動畫效果,這些屬性稱為Animatable Properties(可動畫屬性)。
1> 列舉幾個常見的Animatable Properties:
bounds:用于設置CALayer的寬度和高度。修改這個屬性會產(chǎn)生縮放動畫
backgroundColor:用于設置CALayer的背景色。修改這個屬性會產(chǎn)生背景色的漸變動畫
position:用來設置CALayer在父層中的位置,它是以父層的左上角為坐標原點(0, 0),修改這個屬性會產(chǎn)生平移動畫
anchorPoint:錨點,也稱為"定位點",它決定著CALayer身上的哪個點會在position屬性所指的位置。它的x、y取值范圍都是0~1,默認值為(0.5, 0.5),默認情況下,CALayer的中點會在position所指定的位置上。
6、CALayer自定義層
自定義層,其實就是在層上繪圖
1> 方法描述: 創(chuàng)建一個CALayer的子類,然后覆蓋drawInContext:方法,使用Quartz2D API進行繪圖
第一步:在ZXLayer.h 文件的.m 中
/**
重寫這個方法進行圖形繪制
*/
- (void)drawInContext:(CGContextRef)ctx{
// 設置為藍色
CGContextSetRGBFillColor(ctx,0,0,1,1.0);
CGContextMoveToPoint(ctx,50,0);
// 連到點(0,100)
CGContextAddLineToPoint(ctx,0,100);
// 連到點(100,100)
CGContextAddLineToPoint(ctx,100,100);
// 合并路徑
CGContextClosePath(ctx);
// 繪制路徑
CGContextFillPath(ctx);
}
第二步:在控制器中通過自定義的layer添加圖層
// 通過自定義控件添加圖層
ZXLayer*mLayer = [ZXLayerlayer];
// 設置寬高
mLayer.bounds=CGRectMake(0,0,100,100);
// 設置位置
mLayer.position=CGPointMake(100,100);
// 添加邊框
mLayer.borderColor= [UIColorredColor].CGColor;
mLayer.borderWidth=8;
// 開始繪制圖層 ----- 觸發(fā)drawInContext:方法
[mLayersetNeedsDisplay];
// 添加圖層
[self.view.layeraddSublayer:mLayer];
2> 方法描述:設置CALayer的delegate,然后讓delegate實現(xiàn)drawLayer:inContext:方法,當CALayer需要繪圖時,會調(diào)用delegate的drawLayer:inContext:方法進行繪圖。
注意:不能再將某個UIView設置為CALayer的delegate,因為UIView對象已經(jīng)是它內(nèi)部根層的delegate,再次設置為其他層的delegate就會出問題。UIView和它內(nèi)部CALayer的默認關系圖:
第一步:創(chuàng)建新的層,設置delegate,然后添加到控制器的view的layer中
CALayer*nlayer = [CALayerlayer];
// 設置delegate --- 要遵守協(xié)議 CALayerDelegate
nlayer.delegate=self;
// 設置層的寬高
nlayer.bounds=CGRectMake(0,0,100,100);
// 設置層的位置
nlayer.position=CGPointMake(100,100);
// 開始繪制圖層
[nlayersetNeedsDisplay];
[self.view.layeraddSublayer:nlayer];
第二步:讓CALayer的delegate(前面設置的是控制器)實現(xiàn)drawLayer:inContext:方法
/**
實現(xiàn)代理方法
*/
- (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)ctx{
// 設置藍色
CGContextSetRGBStrokeColor(ctx,0,0,1,1);
// 設置邊框寬度
CGContextSetLineWidth(ctx,10);
// 添加一個跟層一樣大的矩形到路徑中
CGContextAddRect(ctx, layer.bounds);
// 繪制路徑
CGContextStrokePath(ctx);
}
7、UIView的詳細顯示過程
? ? ? ?當UIView需要顯示時,它內(nèi)部的層會準備好一個CGContextRef(圖形上下文),然后調(diào)用delegate(這里就是UIView)的drawLayer:inContext:方法,并且傳入已經(jīng)準備好的CGContextRef對象。而UIView在drawLayer:inContext:方法中又會調(diào)用自己的drawRect:方法
? ? ? ?平時在drawRect:中通過UIGraphicsGetCurrentContext()獲取的就是由層傳入的CGContextRef對象,在drawRect:中完成的所有繪圖都會填入層的CGContextRef中,然后被拷貝至屏幕