本文目錄
一、什么是CALayer
* 在iOS系統(tǒng)中够滑,你能看得見摸得著的東西基本上都是UIView蛤高,比如一個按鈕蚣旱、一個文本標(biāo)簽碑幅、一個文本輸入框、一個圖標(biāo)等等塞绿,這些都是UIView沟涨。
* 其實(shí)UIView之所以能顯示在屏幕上,完全是因?yàn)樗鼉?nèi)部的一個層异吻。
* 在創(chuàng)建UIView對象時裹赴,UIView內(nèi)部會自動創(chuàng)建一個層(即CALayer對象),通過UIView的layer屬性可以訪問這個層诀浪。當(dāng)UIView需要顯示到屏幕上時棋返,會調(diào)用drawRect:方法進(jìn)行繪圖,并且會將所有內(nèi)容繪制在自己的層上雷猪,繪圖完畢后睛竣,系統(tǒng)會將層拷貝到屏幕上,于是就完成了UIView的顯示求摇。
* 換句話說射沟,UIView本身不具備顯示的功能,是它內(nèi)部的層才有顯示功能与境。
二验夯、CALayer的簡單使用
上面已經(jīng)說過了,UIView之所以能夠顯示摔刁,完全是因?yàn)閮?nèi)部的CALayer對象挥转。因此,通過操作這個CALayer對象簸搞,可以很方便地調(diào)整UIView的一些界面屬性扁位,比如:陰影、圓角大小趁俊、邊框?qū)挾群皖伾取?/p>
1.CALayer是被定義在QuartzCore框架中的域仇,因此要想使用CALayer,先導(dǎo)入QuartzCore框架
1> 點(diǎn)擊項(xiàng)目名稱寺擂,然后點(diǎn)擊右邊TARGETS下面的target
2> 點(diǎn)擊Build Pases后暇务,展開Link Binary....,添加 + 號
3> 在搜索框中輸入"Quartz"怔软,選中QuartzCore.framework垦细,最后add添加
4> 添加完畢后,這個框架就會出現(xiàn)在項(xiàng)目文件夾中
如果你覺得位置不好看挡逼,還可以將它拖到Frameworks文件夾下括改,跟其他框架放一起
2.在項(xiàng)目代碼中導(dǎo)入QuartzCore框架的主頭文件
#import
3.通過CALayer修改UIImageView的界面屬性
你也可以使用UIButton或者UILabel,這里就以UIImageView為例子
1> 先創(chuàng)建一個UIImageView家坎,添加到控制器的view中
1UIImage *image = [UIImage imageNamed:@"lufy.png"];2UIImageView *imageView =[[[UIImageView alloc] initWithImage:image] autorelease];3imageView.center = CGPointMake(100,100);4[self.view addSubview:imageView];
2> 設(shè)置陰影
1imageView.layer.shadowColor=[UIColor grayColor].CGColor;2imageView.layer.shadowOffset= CGSizeMake(10,10);3imageView.layer.shadowOpacity=0.5;
* 第1行設(shè)置陰影的顏色為灰色嘱能,注意吝梅,這里使用的是UIColor的CGColor屬性,是一種CGColorRef類型的數(shù)據(jù)
* 第2行設(shè)置陰影的偏移大小惹骂,可以看出陰影往原圖的右下角偏移
* 第3行設(shè)置陰影的不透明度為0.5苏携,表示半透明。如果為1对粪,代表完全不透明右冻。
3>設(shè)置圓角大小
通過layer屬性可以訪問視圖內(nèi)部的CALayer對象
1imageView.layer.cornerRadius=10;2imageView.layer.masksToBounds= YES;
* 第1行設(shè)置圓角半徑為10
* 第2行的maskToBounds=YES:可以看做是強(qiáng)制內(nèi)部的所有子層支持圓角效果,少了這個設(shè)置著拭,UIImageView是不會有圓角效果的
* 注意纱扭,如果設(shè)置了maskToBounds=YES,那將不會有陰影效果
4> 設(shè)置邊框?qū)挾群皖伾?/p>
1imageView.layer.borderWidth=5;2imageView.layer.borderColor= [UIColor redColor].CGColor;
* 第1行設(shè)置邊框?qū)挾葹?
* 第2行設(shè)置邊框顏色為紅色
5> 設(shè)置旋轉(zhuǎn)
imageView.layer.transform=CATransform3DMakeRotation(M_PI_4,0,0,1);
* 利用transform屬性可以設(shè)置旋轉(zhuǎn)茫死、縮放等效果
* M_PI_4表示四分之π跪但,順時針旋轉(zhuǎn)45°
* 后面的(0, 0, 1)表示Z軸這個向量,修改這個向量可以做一些三維旋轉(zhuǎn)效果峦萎,你可以隨便改個值試一下,比如(1, 1, 1)
* 總體的意思是layer會繞著Z軸順時針旋轉(zhuǎn)45°忆首,也就是在x爱榔、y平面進(jìn)行旋轉(zhuǎn)
本文目錄
三详幽、為什么CALayer中使用CGColorRef和CGImageRef這2種數(shù)據(jù)類型,而不用UIColor和UIImage浸锨?
*上一講已經(jīng)說過柱搜,UIView內(nèi)部默認(rèn)有個CALayer對象(層)迟郎,通過layer屬性可以訪問這個層。要注意的是聪蘸,這個默認(rèn)的層不允許重新創(chuàng)建宪肖,但可以往層里面添加子層
*UIView可以通過addSubview:方法添加子視圖,類似地健爬,CALayer可以通過addSublayer:方法添加子層
接下來演示一下如何添加子層:
一控乾、添加一個簡單的圖層
1CALayer *myLayer =[CALayerlayer];2//設(shè)置層的寬度和高度(100x100)3myLayer.bounds= CGRectMake(0,0,100,100);4//設(shè)置層的位置5myLayer.position= CGPointMake(100,100);6//設(shè)置層的背景顏色:紅色7myLayer.backgroundColor=[UIColor redColor].CGColor;8//設(shè)置層的圓角半徑為109myLayer.cornerRadius=10;1011//添加myLayer到控制器的view的layer中12[self.view.layeraddSublayer:myLayer];
* 第1行創(chuàng)建了一個自動釋放的CALayer對象,你也可以使用經(jīng)典的alloc和init方法來創(chuàng)建
* 第12行將創(chuàng)建好的層添加到控制器的view的層中
二娜遵、添加一個顯示圖片的圖層
1CALayer *myLayer =[CALayerlayer];2//設(shè)置層的寬度和高度(100x100)3myLayer.bounds= CGRectMake(0,0,100,100);4//設(shè)置層的位置5myLayer.position= CGPointMake(100,100);6//設(shè)置需要顯示的圖片7myLayer.contents= (id)[UIImage imageNamed:@"lufy.png"].CGImage;8//設(shè)置層的圓角半徑為109myLayer.cornerRadius=10;10//如果設(shè)置了圖片蜕衡,需要設(shè)置這個屬性為YES才有圓角效果11myLayer.masksToBounds=YES;1213//添加myLayer到控制器的view的layer中14[self.view.layeraddSublayer:myLayer];
* 在第7行設(shè)置需要顯示的圖片,注意设拟,這里用的是UIImage的CGImage屬性慨仿,是一種CGImageRef類型的數(shù)據(jù)
三鸽扁、為什么CALayer中使用CGColorRef和CGImageRef這2種數(shù)據(jù)類型,而不用UIColor和UIImage镶骗?
* 首先要知道:CALayer是定義在QuartzCore框架中的桶现;CGImageRef、CGColorRef兩種數(shù)據(jù)類型是定義在CoreGraphics框架中的鼎姊;UIColor骡和、UIImage是定義在UIKit框架中的
* 其次,QuartzCore框架和CoreGraphics框架是可以跨平臺使用的相寇,在iOS和Mac OS X上都能使用慰于,但是UIKit只能在iOS中使用
* 因此,為了保證可移植性唤衫,QuartzCore不能使用UIImage婆赠、UIColor,只能使用CGImageRef佳励、CGColorRef
* 不過很多情況下休里,可以通過UIKit對象的特定方法,得到CoreGraphics對象赃承,比如UIImage的CGImage方法可以返回一個CGImageRef
四妙黍、UIView和CALayer的選擇
細(xì)心的朋友不難發(fā)現(xiàn),其實(shí)前面的2個效果不僅可以通過添加層來實(shí)現(xiàn)瞧剖,還可以通過添加UIView來實(shí)現(xiàn)拭嫁。比如,第1個紅色的層可以用一個UIView來實(shí)現(xiàn)抓于,第2個顯示圖片的層可以用一個UIImageView來實(shí)現(xiàn)做粤。既然CALayer和UIView都能實(shí)現(xiàn)相同的顯示效果,那究竟該選擇誰好呢捉撮?
* 其實(shí)怕品,對比CALayer,UIView多了一個事件處理的功能呕缭。也就是說堵泽,CALayer不能處理用戶的觸摸事件,而UIView可以
* 所以恢总,如果顯示出來的東西需要跟用戶進(jìn)行交互的話迎罗,用UIView;如果不需要跟用戶進(jìn)行交互片仿,用UIView或者CALayer都可以
* 當(dāng)然纹安,CALayer的性能會高一些,因?yàn)樗倭耸录幚淼墓δ埽虞p量級
五厢岂、UIView和CALayer的其他關(guān)系
*UIView可以通過subviews屬性訪問所有的子視圖光督,類似地,CALayer也可以通過sublayers屬性訪問所有的子層
*UIView可以通過superview屬性訪問父視圖塔粒,類似地结借,CALayer也可以通過superlayer屬性訪問父層
* 下面再看一張UIView和CALayer的關(guān)系圖:
如果兩個UIView是父子關(guān)系,那么它們內(nèi)部的CALayer也是父子關(guān)系卒茬。
本文目錄
一圃酵、隱式動畫屬性
* 在前面幾講中已經(jīng)提到柳畔,每一個UIView內(nèi)部都默認(rèn)關(guān)聯(lián)著一個CALayer,我們可用稱這個Layer為Root Layer(根層)郭赐。所有的非Root Layer薪韩,也就是手動創(chuàng)建的CALayer對象,都存在著隱式動畫捌锭。
* 當(dāng)對非Root Layer的部分屬性進(jìn)行相應(yīng)的修改時俘陷,默認(rèn)會自動產(chǎn)生一些動畫效果,這些屬性稱為Animatable Properties(可動畫屬性)舀锨。
* 列舉幾個常見的Animatable Properties:
bounds:用于設(shè)置CALayer的寬度和高度岭洲。修改這個屬性會產(chǎn)生縮放動畫
backgroundColor:用于設(shè)置CALayer的背景色。修改這個屬性會產(chǎn)生背景色的漸變動畫
position:用于設(shè)置CALayer的位置坎匿。修改這個屬性會產(chǎn)生平移動畫
比如:假設(shè)一開始CALayer的position為(100, 100),然后在某個時刻修改為(200, 200)雷激,那么整個CALayer就會在短時間內(nèi)從(100, 100)這個位置平移到(200, 200)
* 我們也可以從官方文檔中查詢所有的Animatable Properties
1.點(diǎn)擊Window -> Organizer
2.在搜索框輸入"animatable"即可
二替蔬、position和anchorPoint
* position和anchorPoint屬性都是CGPoint類型的
* position可以用來設(shè)置CALayer在父層中的位置,它是以父層的左上角為坐標(biāo)原點(diǎn)(0, 0)
* anchorPoint稱為"定位點(diǎn)"屎暇,它決定著CALayer身上的哪個點(diǎn)會在position屬性所指的位置承桥。它的x、y取值范圍都是0~1根悼,默認(rèn)值為(0.5, 0.5)
1.創(chuàng)建一個CALayer凶异,添加到控制器的view的layer中
1CALayer *myLayer =[CALayer layer];2//設(shè)置層的寬度和高度(100x100)3myLayer.bounds= CGRectMake(0,0,100,100);4//設(shè)置層的位置5myLayer.position= CGPointMake(100,100);6//設(shè)置層的背景顏色:紅色7myLayer.backgroundColor=[UIColor redColor].CGColor;89//添加myLayer到控制器的view的layer中10[self.view.layer addSublayer:myLayer];
第5行設(shè)置了myLayer的position為(100, 100),又因?yàn)閍nchorPoint默認(rèn)是(0.5, 0.5)挤巡,所以最后的效果是:myLayer的中點(diǎn)會在父層的(100, 100)位置
注意剩彬,藍(lán)色線是我自己加上去的,方便大家理解矿卑,并不是默認(rèn)的顯示效果喉恋。兩條藍(lán)色線的寬度均為100。
2.若將anchorPoint改為(0, 0),myLayer的左上角會在(100, 100)位置
1myLayer.anchorPoint= CGPointMake(0,0);
3.若將anchorPoint改為(1, 1)轻黑,myLayer的右下角會在(100, 100)位置
1myLayer.anchorPoint= CGPointMake(1,1);
4.將anchorPoint改為(0, 1)糊肤,myLayer的左下角會在(100, 100)位置
1myLayer.anchorPoint = CGPointMake(0,1);
我想,你應(yīng)該已經(jīng)明白anchorPoint的用途了吧氓鄙,它決定著CALayer身上的哪個點(diǎn)會在position所指定的位置上馆揉。它的x、y取值范圍都是0~1抖拦,默認(rèn)值為(0.5, 0.5)升酣,因此,默認(rèn)情況下蟋座,CALayer的中點(diǎn)會在position所指定的位置上拗踢。當(dāng)anchorPoint為其他值時,以此類推向臀。
本文目錄
自定義層君纫,其實(shí)就是在層上繪圖,一共有2種方法芹彬,下面詳細(xì)介紹一下蓄髓。
一、自定義層的方法1
方法描述:創(chuàng)建一個CALayer的子類舒帮,然后覆蓋drawInContext:方法会喝,使用Quartz2D API進(jìn)行繪圖
1.創(chuàng)建一個CALayer的子類
2.在.m文件中覆蓋drawInContext:方法,在里面繪圖
1@implementation MJLayer23#pragmamark 繪制一個實(shí)心三角形4- (void)drawInContext:(CGContextRef)ctx {5//設(shè)置為藍(lán)色6CGContextSetRGBFillColor(ctx,0,0,1,1);789//設(shè)置起點(diǎn)10CGContextMoveToPoint(ctx,50,0);11//從(50, 0)連線到(0, 100)12CGContextAddLineToPoint(ctx,0,100);13//從(0, 100)連線到(100, 100)14CGContextAddLineToPoint(ctx,100,100);15//合并路徑玩郊,連接起點(diǎn)和終點(diǎn)16CGContextClosePath(ctx);1718//繪制路徑19CGContextFillPath(ctx);20}2122@end
3.在控制器中添加圖層到屏幕上
1MJLayer *layer =[MJLayer layer];2//設(shè)置層的寬高3layer.bounds= CGRectMake(0,0,100,100);4//設(shè)置層的位置5layer.position= CGPointMake(100,100);6//開始繪制圖層7[layersetNeedsDisplay];8[self.view.layer addSublayer:layer];
注意第7行肢执,需要調(diào)用setNeedsDisplay這個方法,才會觸發(fā)drawInContext:方法的調(diào)用译红,然后進(jìn)行繪圖
二预茄、自定義層的方法2
方法描述:設(shè)置CALayer的delegate,然后讓delegate實(shí)現(xiàn)drawLayer:inContext:方法侦厚,當(dāng)CALayer需要繪圖時耻陕,會調(diào)用delegate的drawLayer:inContext:方法進(jìn)行繪圖。
* 這里要注意的是:不能再將某個UIView設(shè)置為CALayer的delegate刨沦,因?yàn)閁IView對象已經(jīng)是它內(nèi)部根層的delegate诗宣,再次設(shè)置為其他層的delegate就會出問題。UIView和它內(nèi)部CALayer的默認(rèn)關(guān)系圖:
1.創(chuàng)建新的層已卷,設(shè)置delegate梧田,然后添加到控制器的view的layer中
1CALayer *layer =[CALayer layer];2//設(shè)置delegate3layer.delegate=self;4//設(shè)置層的寬高5layer.bounds= CGRectMake(0,0,100,100);6//設(shè)置層的位置7layer.position= CGPointMake(100,100);8//開始繪制圖層9[layersetNeedsDisplay];10[self.view.layer addSublayer:layer];
* 在第3行設(shè)置了CALayer的delegate淳蔼,這里的self是指控制器
*注意第9行,需要調(diào)用setNeedsDisplay這個方法裁眯,才會通知delegate進(jìn)行繪圖
2.讓CALayer的delegate(前面設(shè)置的是控制器)實(shí)現(xiàn)drawLayer:inContext:方法
1#pragmamark 畫一個矩形框2- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {3//設(shè)置藍(lán)色4CGContextSetRGBStrokeColor(ctx,0,0,1,1);5//設(shè)置邊框?qū)挾?CGContextSetLineWidth(ctx,10);78//添加一個跟層一樣大的矩形到路徑中9CGContextAddRect(ctx, layer.bounds);1011//繪制路徑12CGContextStrokePath(ctx);13}
三鹉梨、其他
1.總結(jié)
無論采取哪種方法來自定義層,都必須調(diào)用CALayer的setNeedsDisplay方法才能正常繪圖穿稳。
2.UIView的詳細(xì)顯示過程
* 當(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中它改,然后被拷貝至屏幕