CALayer
概念
在iOS中擂送,你能看得見摸得著的東西基本上都是UIView翘悉,比如一個按鈕、一個文本標(biāo)簽待秃、一個文本輸入框拜秧、一個圖標(biāo)等等,這些都是UIView,其實UIView之所以能顯示在屏幕上章郁,完全是因為它內(nèi)部的一個圖層
在創(chuàng)建UIView對象時枉氮,UIView內(nèi)部會自動創(chuàng)建一個圖層(即CALayer對象),通過UIView的layer屬性可以訪問這個層 @property(nonatomic,readonly,retain) CALayer *layer;
當(dāng)UIView需要顯示到屏幕上時,會調(diào)用drawRect:方法進(jìn)行繪圖聊替,并且會將所有內(nèi)容繪制在自己的圖層上楼肪,繪圖完畢后,系統(tǒng)會將圖層拷貝到屏幕上惹悄,于是就完成了UIView的顯示,換句話說淹辞,UIView本身不具備顯示的功能,是它內(nèi)部的層才有顯示功能
基本屬性
寬度和高度@propertyCGRectbounds;位置(默認(rèn)指中點俘侠,具體由anchorPoint決定)@propertyCGPointposition;錨點(x,y的范圍都是0-1)象缀,決定了position的含義@propertyCGPointanchorPoint;背景顏色(CGColorRef類型)@propertyCGColorRefbackgroundColor;形變屬性@propertyCATransform3Dtransform;邊框顏色(CGColorRef類型)@propertyCGColorRefborderColor;邊框?qū)挾菮propertyCGFloatborderWidth;圓角半徑@propertyCGColorRefborderColor;內(nèi)容(比如設(shè)置為圖片CGImageRef)@property(retain)idcontents;
基本使用
通過操作CALayer對象,可以很方便地調(diào)整UIView的一些外觀屬性爷速,比如: 陰影 圓角大小 邊框?qū)挾群皖伾?… …
還可以給圖層添加動畫央星,來實現(xiàn)一些比較炫酷的效果
1操作layer改變UIView外觀.1.1設(shè)置陰影? ? ? ? 默認(rèn)圖層是有陰影的, 只不過,是透明的self.RedView.layer.shadowOpacity=1;? ? ? ? 設(shè)置陰影的圓角self.RedView.layer.shadowRadius=10;? ? ? ? 設(shè)置陰影的顏色,把UIKit轉(zhuǎn)換成CoreGraphics框架,用.CG開頭self.RedView.layer.shadowColor= [UIColorblueColor].CGColor;1.2.設(shè)置邊框? ? ? ? 設(shè)置圖層邊框,在圖層中使用CoreGraphics的CGColorRefself.RedView.layer.borderColor= [UIColorwhiteColor].CGColor;self.RedView.layer.borderWidth=2;1.3.設(shè)置圓角? ? ? ? 圖層的圓角半徑,圓角半徑為寬度的一半, 就是一個圓self.RedView.layer.cornerRadius=50;2.操作layer改變UIImageView的外觀.2.1設(shè)置圖形邊框self.imageView.layer.borderWidth=2;self.imageView.layer.borderColor= [UIColorwhiteColor].CGColor;2.2設(shè)置圖片的圓角半徑self.imageView.layer.cornerRadius=50;? ? ? ? 裁剪,超出裁剪區(qū)域的部分全部裁剪掉self.imageView.layer.masksToBounds=YES;? ? ? ? 注意:UIImageView當(dāng)中Image并不是直接添加在層上面的.這是添加在layer當(dāng)中的contents里.? ? ? ? 我們設(shè)置層的所有屬性它只作用在層上面.對contents里面的東西并不起作用.所以我們看不到圖片有圓角的效果.? ? ? ? 想要讓圖片有圓角的效果.可以把masksToBounds這個屬性設(shè)為YES,? ? ? ? 當(dāng)設(shè)為YES,把就會把超過根層以外的東西都給裁剪掉.3.layer的CATransform3D屬性.? ? ? 只有旋轉(zhuǎn)的時候才可以看出3D的效果.? ? ? 旋轉(zhuǎn)? ? ? x,y,z 分別代表x,y,z軸.CATransform3DMakeRotation(M_PI,1,0,0);? ? ? 平移CATransform3DMakeTranslation(x,y,z)? ? ? 縮放CATransform3DMakeScale(x,y,z);? ? ? 可以通過KVC的方式進(jìn)行設(shè)置屬性.? ? ? 但是CATransform3DMakeRotation它的值,是一個結(jié)構(gòu)體, 所以要把結(jié)構(gòu)轉(zhuǎn)成對象.NSValue*value = [NSValuevalueWithCATransform3D:CATransform3DMakeRotation(M_PI,1,0,0)];? ? ? [_imageView.layersetValue:value forKeyPath:@"transform.scale"];? ? ? 什么時候用KVC?? ? ? 當(dāng)需要做一些快速縮放,平移,二維的旋轉(zhuǎn)時用KVC.? ? ? 比如: [_imageView.layersetValue:@0.5forKeyPath:@"transform.scale"];? ? ? 快速的進(jìn)行縮放.? ? ? 后面forKeyPath屬性值不是亂寫的.蘋果文檔當(dāng)中給了相關(guān)的屬性.
UIKit -> CG
首先要知道: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
自定義CAlayer
1.如何自定義Layer.? ? 自定義CALayer的方式創(chuàng)建UIView的方式非常相似.CALayer*layer = [CALayerlayer];? ? layer.frame=CGRectMake(50,50,100,100);? ? layer.backgroundColor= [UIColorredColor].CGColor;? ? [self.view.layeraddSublayer:layer];? ? 給layer設(shè)置圖片.? ? layer.contents= (id)[UIImageimageNamed:@"阿貍頭像"].CGImage;
UIView和CALayer的選擇
通過CALayer,就能做出跟UIImageView一樣的界面效果
對比CALayer篙梢,UIView多了一個事件處理的功能顷帖。也就是說,CALayer不能處理用戶的觸摸事件渤滞,而UIView可以.所以贬墩,如果顯示出來的東西需要跟用戶進(jìn)行交互的話,用UIView蔼水;如果不需要跟用戶進(jìn)行交互震糖,用UIView或者CALayer都可以,當(dāng)然录肯,CALayer的性能會高一些趴腋,因為它少了事件處理的功能,更加輕量級
UIView可以通過subviews屬性訪問所有的子視圖,類似地优炬,CALayer也可以通過sublayers屬性訪問所有的子層
UIView可以通過superview屬性訪問父視圖颁井,類似地,CALayer也可以通過superlayer屬性訪問父層
下面再看一張UIView和CALayer的關(guān)系圖:

如果兩個UIView是父子關(guān)系蠢护,那么它們內(nèi)部的CALayer也是父子關(guān)系雅宾。
position和anchorPoint
@propertyCGPointposition;用來設(shè)置CALayer在父層中的位置以父層的左上角為原點(0,0)@propertyCGPointanchorPoint;稱為“定位點”、“錨點”決定著CALayer身上的哪個點會在position屬性所指的位置以自己的左上角為原點(0,0)它的x葵硕、y取值范圍都是0~1眉抬,默認(rèn)值為(0.5,0.5)
如圖


隱式動畫
根層:UIView內(nèi)部自動關(guān)聯(lián)著的那個layer我們稱它是根層.
非根層:自己手動創(chuàng)建的層,稱為非根層.
隱式動畫就是當(dāng)對非根層的部分屬性進(jìn)行修改時,它會自動的產(chǎn)生一些動畫的效果.我們稱這個默認(rèn)產(chǎn)生的動畫為隱式動畫.
如何取消隱式動畫 首先要了解動畫底層是怎么做的.動畫的底層是包裝成一個事務(wù)(很多操作綁定在一起,當(dāng)這些操作執(zhí)行完畢后,才去執(zhí)行下一個操作.)來進(jìn)行的.
開啟事務(wù)? ? [CATransactionbegin];? ? 設(shè)置事務(wù)沒有動畫? ? [CATransactionsetDisableActions:YES];? ? 設(shè)置動畫執(zhí)行的時長? ? [CATransactionsetAnimationDuration:2];? ? 提交事務(wù)? ? [CATransactioncommit];
每一個UIView內(nèi)部都默認(rèn)關(guān)聯(lián)著一個CALayer,我們可用稱這個Layer為Root Layer(根層)
所有的非Root Layer懈凹,也就是手動創(chuàng)建的CALayer對象蜀变,都存在著隱式動畫
隱式動畫是指當(dāng)對非RootLayer的部分屬性進(jìn)行修改時,默認(rèn)會自動產(chǎn)生一些動畫效果而這些屬性稱為Animatable,Properties(可動畫屬性)
列舉幾個常見的Animatable Properties:
1->bounds:用于設(shè)置CALayer的寬度和高度介评。修改這個屬性會產(chǎn)生縮放動畫
2->backgroundColor:用于設(shè)置CALayer的背景色库北。修改這個屬性會產(chǎn)生背景色的漸變動畫
3->position:用于設(shè)置CALayer的位置。修改這個屬性會產(chǎn)生平移動畫
時鐘效果
1.搭建界面.? ? ? ? 分析界面.? ? ? ? 界面上時針,分針,秒針不需要與用戶進(jìn)行交互.所以都可以使用layer方式來做.? ? ? ? 做之前要觀察時針在做什么效果.? ? ? ? 是根據(jù)當(dāng)前的時間,繞著表盤的中心點進(jìn)行旋轉(zhuǎn).? ? ? ? 要了解一個非常重要的知識點.無論是旋轉(zhuǎn),縮放它都是繞著錨點.進(jìn)行的.? ? ? ? 要想讓時針,分針,稱針顯示的中間,還要繞著中心點進(jìn)行旋轉(zhuǎn).? ? ? ? 那就要設(shè)置它的position和anchorPoint兩個屬性.? ? ? ? 創(chuàng)建秒針CALayer*layer = [CALayerlayer];? ? ? ? _secLayer = layer;? ? ? ? layer.bounds=CGRectMake(0,0,1,80);? ? ? ? layer.anchorPoint=CGPointMake(0.5,1);? ? ? ? layer.position=CGPointMake(_clockView.bounds.size.width*0.5,? ? _clockView.bounds.size.height*0.5);? ? ? ? layer.backgroundColor= [UIColorredColor].CGColor;? ? ? ? [_clockView.layeraddSublayer:layer];2.讓秒針開始旋轉(zhuǎn).? ? ? ? 讓秒針旋轉(zhuǎn).所以要計算當(dāng)前的旋轉(zhuǎn)度是多少?? ? ? ? 當(dāng)前的旋轉(zhuǎn)角度為:當(dāng)前的時間 * 每秒旋轉(zhuǎn)多少度.? ? ? ? 計算每一秒旋轉(zhuǎn)多少度.60秒轉(zhuǎn)一圈360度360除以60就是每一秒轉(zhuǎn)多少度.每秒轉(zhuǎn)6度.? ? ? ? 獲取當(dāng)前的時間? ? ? ? 創(chuàng)建日歷類NSCalendar*calendar = [NSCalendarcurrentCalendar];? ? ? ? 把日歷類轉(zhuǎn)換成一個日期組件? ? ? ? 日期組件(年,月,日,時,分,秒)? ? ? ? component:日期組件有哪些東西組成,他是一個枚舉,里面有年月日時分秒? ? ? ? fromDate:當(dāng)前的日期NSDateComponents*cmp = [calendar components:NSCalendarUnitSecondfromDate:[NSDatedate]];? ? ? ? 我們的秒就是保存在日期組件里面,它里面提供了很多get方法.NSIntegersecond = cmp.second;? ? ? ? 那么當(dāng)前秒針旋轉(zhuǎn)的角度就是? ? ? ? 當(dāng)前的秒數(shù)乘以每秒轉(zhuǎn)多少度.? ? ? ? second * perSecA? ? ? ? 還得要把角度轉(zhuǎn)換成弧度.? ? ? ? 因為下面分針,時針也得要用到, 就把它抽出一個速參數(shù)的宏.#define angle2Rad(angle) ((angle) / 180.0 * M_PI)讓它每隔一秒旋轉(zhuǎn)一次.所以添加一個定時器.? ? ? ? 每個一秒就調(diào)用,旋轉(zhuǎn)秒針? ? ? ? - (void)timeChange{? ? ? ? 獲取當(dāng)前的秒數(shù)? ? ? ? 創(chuàng)建日歷類NSCalendar*calendar = [NSCalendarcurrentCalendar];? ? ? ? 把日歷類轉(zhuǎn)換成一個日期組件? ? ? ? 日期組件(年,月,日,時,分,秒)? ? ? ? component:日期組件有哪些東西組成,他是一個枚舉,里面有年月日時分秒? ? ? ? fromDate:當(dāng)前的日期NSDateComponents*cmp = [calendar components:NSCalendarUnitSecondfromDate:[NSDatedate]];? ? ? ? 我們的秒就是保存在日期組件里面,它里面提供了很多get方法.NSIntegersecond = cmp.second;? ? ? ? 秒針旋轉(zhuǎn)多少度.CGFloatangel = angle2Rad(second * perSecA);? ? ? ? 旋轉(zhuǎn)秒針self.secondL.transform=CATransform3DMakeRotation(angel,0,0,1);? ? ? ? }? ? ? ? 運行發(fā)現(xiàn)他會一下只就調(diào)到某一個時間才開始旋轉(zhuǎn)? ? ? ? 一開始的時候就要來到這個方法,獲取當(dāng)前的秒數(shù)把它定位好.? ? ? ? 要在添加定時器之后就調(diào)用一次timeChange方法.3.添加分針? ? ? ? 快速拷貝一下,然后添加一個分針成員屬性.? ? ? ? 修改寬度,修改顏色? ? ? ? 也得要讓它旋轉(zhuǎn),? ? ? ? 要算出每分鐘轉(zhuǎn)多少度? ? ? ? 轉(zhuǎn)60分鐘剛好是一圈? ? ? ? 所以每一分鐘也是轉(zhuǎn)6度.? ? ? ? 獲取當(dāng)前多少分?? ? ? ? 同樣是在日期組件里面獲得? ? ? ? 里面有左移符號,右移符號.他就可以用一個并運算? ? ? ? 現(xiàn)在同時讓他支持秒數(shù)和分 后面直接加上一個 |NSDateComponents*cmp = [calendar components:NSCalendarUnitSecond|NSCalendarUnitMinutefromDate:[NSDatedate]];CGFloatminueteAngel = angle2Rad(minute * perMinuteA);self.minueL.transform=CATransform3DMakeRotation(minueteAngel,0,0,1);4.添加時針? ? ? ? ? 同樣復(fù)制之前的,添加一個小時屬性? ? ? ? 小時轉(zhuǎn)多少度? ? ? ? 當(dāng)前是多少小時,再計算先每一小時轉(zhuǎn)多少度.12個小時轉(zhuǎn)一圈.360除以12,每小時轉(zhuǎn)30度? ? ? ? 時針旋轉(zhuǎn)多少度CGFloathourAngel = angle2Rad(hour * perHourA);? ? ? ? 旋轉(zhuǎn)時針self.hourL.transform=CATransform3DMakeRotation(hourAngel,0,0,1);? ? ? ? 直接這樣寫會有問題? ? ? ? 就是沒轉(zhuǎn)一分鐘,小時也會移動一點點? ? ? ? 接下來要算出,每一分鐘,小時要轉(zhuǎn)多少度60分鐘一小時.一小時轉(zhuǎn)30度.30除以60,就是每一分鐘,時針轉(zhuǎn)多少度.0.5時針旋轉(zhuǎn)多少度CGFloathourAngel = angle2Rad(hour * perHourA + minute * perMinuteHourA);? ? ? ? 旋轉(zhuǎn)時針self.hourL.transform=CATransform3DMakeRotation(hourAngel,0,0,1);