文 || 張賀
- 在iOS中号涯,你能看得見摸得著的東西基本上都是UIView,比如一個(gè)按鈕锯七、一個(gè)文本標(biāo)簽链快、一個(gè)文本輸入框、一個(gè)圖標(biāo)等等眉尸,這些都是UIView
- 其實(shí)UIView之所以能顯示在屏幕上域蜗,完全是因?yàn)樗鼉?nèi)部的一個(gè)圖層
- 在創(chuàng)建UIView對(duì)象時(shí)巨双,UIView內(nèi)部會(huì)自動(dòng)創(chuàng)建一個(gè)圖層(即CALayer對(duì)象),通過UIView的layer屬性可以訪問這個(gè)層
@property(nonatomic,readonly,strong) CALayer *layer; // returns view's layer. Will always return a non-nil value. view is layer's delegate - 當(dāng)UIView需要顯示到屏幕上時(shí)霉祸,會(huì)調(diào)用drawRect:方法進(jìn)行繪圖筑累,并且會(huì)將所有內(nèi)容繪制在自己的圖層上,繪圖完畢后丝蹭,系統(tǒng)會(huì)將圖層拷貝到屏幕上慢宗,于是就完成了UIView的顯示
- 換句話說,UIView本身不具備顯示的功能奔穿,是它內(nèi)部的層才有顯示功能
CALayer的基本使用
- 通過操作CALayer對(duì)象镜沽,可以很方便地調(diào)整UIView的一些外觀屬性,比如:
- 陰影
- 圓角大小
- 邊框?qū)挾群皖伾?/li>
- ... ...
- 還可以給圖層添加動(dòng)畫贱田,來實(shí)現(xiàn)一些比較炫酷的效果
陰影
shadowOffset(陰影的偏移量)缅茉,默認(rèn)是(0, -3)。
/* The shadow offset. Defaults to (0, -3). Animatable. */
@property CGSize shadowOffset;
所以UIView自帶陰影效果男摧,但為什么看不見呢蔬墩?是因?yàn)樗牧硗庖粋€(gè)屬性-
shadowOpacity(陰影的不透明度)默認(rèn)為0,也就是說自帶的(0, -3)的偏移量是透明的
/* The opacity of the shadow. Defaults to 0. Specifying a value outside the
* [0,1] range will give undefined results. Animatable. */
@property float shadowOpacity;
想要看見這(0, -3)的偏移量只需要把shadowOpacity設(shè)置為1
self.purpleView.layer.shadowOpacity = 1;
也可以自己設(shè)置偏移量
self.purpleView.layer.shadowOffset = CGSizeMake(20, 10);
-
shadowColor(陰影的顏色)
/* The color of the shadow. Defaults to opaque black. Colors created * from patterns are currently NOT supported. Animatable. */ @property(nullable) CGColorRef shadowColor;
這里要轉(zhuǎn)成CGColor耗拓?
首先
CALayer是定義在QuartzCore框架中的
CGImageRef筹我、CGColorRef 兩種數(shù)據(jù)類型是定義在CoreGraphics框架中的
UIColor、UIImage是定義在 UIKit框架中的其次
QuartzCore框架和CoreGraphics框架是可以跨平臺(tái)使用的帆离,在iOS和Mac OS X上都能使用蔬蕊,但是UIKit只能在iOS中使用-
所以
為了保證可移植性,QuartzCore不能使用UIColor哥谷、UIImage岸夯,只能使用CGColorRef、CGImageRefself.purpleView.layer.shadowColor = [UIColor orangeColor].CGColor;
-
shadowRadius(陰影的模糊程度)
/* The blur radius used to create the shadow. Defaults to 3. Animatable. */ @property CGFloat shadowRadius;
邊框
-
borderWidth(邊框?qū)挾龋?br> /* The width of the layer's border, inset from the layer bounds. The
* border is composited above the layer's content and sublayers and
* includes the effects of the `cornerRadius' property. Defaults to
* zero. Animatable. */@property CGFloat borderWidth;
-
borderColor(邊框的顏色)
/* The color of the layer's border. Defaults to opaque black. Colors
* created from tiled patterns are supported. Animatable. */@property(nullable) CGColorRef borderColor;
這里的顏色也要裝換成CGColor
self.purpleView.layer.borderWidth = 2;
self.purpleView.layer.borderColor = [UIColor orangeColor].CGColor;
圓角
-
cornerRadius(圓角)
/* When positive, the background of the layer will be drawn with
* rounded corners. Also effects the mask generated by the
* `masksToBounds' property. Defaults to zero. Animatable. */@property CGFloat cornerRadius;
注意:設(shè)置圖片圓角的時(shí)候要設(shè)置masksToBounds =YES
這是因?yàn)槲覀冊O(shè)置的所有l(wèi)ayer屬性之作用在根層上layer.contents
只要設(shè)置了layer.masksToBounds =YES
超出根層之外的部分會(huì)被裁掉们妥。
3D
- transform
利用layer的transform屬性可以做一些3D動(dòng)畫
UIView的transform屬性是CGAffineTransform類型的猜扮,而layer的transform屬性是CATransform3D類型的
//平移
self.purpleView.layer.transform = CATransform3DMakeTranslation(100, 0, 0);
//旋轉(zhuǎn)
self.purpleView.layer.transform = CATransform3DMakeRotation(M_PI, 1, 0, 0);
//縮放
self.purpleView.layer.transform = CATransform3DMakeScale(0.5, 0.5, 0);
當(dāng)做一些快速縮放、平移监婶、二維旋轉(zhuǎn)的時(shí)候建議使用KVC
[self.purpleView.layer setValue:@(9) forKeyPath:@"transform.scale"];
可用的keyPath
UIView和CALayer的選擇
通過CALayer旅赢,就能做出跟UIImageView一樣的界面效果
既然CALayer和UIView都能實(shí)現(xiàn)相同的顯示效果,那究竟該選擇誰好呢惑惶?
- 其實(shí)煮盼,對(duì)比CALayer,UIView多了一個(gè)事件處理的功能带污。也就是說僵控,CALayer不能處理用戶的觸摸事件,而UIView可以
- 所以鱼冀,如果顯示出來的東西需要跟用戶進(jìn)行交互的話报破,用UIView悠就;如果不需要跟用戶進(jìn)行交互,用UIView或者CALayer都可以
- 當(dāng)然充易,CALayer的性能會(huì)高一些梗脾,因?yàn)樗倭耸录幚淼墓δ埽虞p量級(jí)
position和anchorPoint
-
CALayer有2個(gè)非常重要的屬性:position和anchorPoint
/* The position in the superlayer that the anchor point of the layer's * bounds rect is aligned to. Defaults to the zero point. Animatable. */ //用來設(shè)置CALayer在父層中的位置 //以父層的左上角為原點(diǎn)(0, 0) @property CGPoint position; /* Defines the anchor point of the layer's bounds rect, as a point in * normalized layer coordinates - '(0, 0)' is the bottom left corner of * the bounds rect, '(1, 1)' is the top right corner. Defaults to * '(0.5, 0.5)', i.e. the center of the bounds rect. Animatable. */ //稱為“定位點(diǎn)”盹靴、“錨點(diǎn)” //決定著CALayer身上的哪個(gè)點(diǎn)會(huì)在position屬性所指的位置 //以自己的左上角為原點(diǎn)(0, 0) //它的x藐唠、y取值范圍都是0~1,默認(rèn)值為(0.5, 0.5) @property CGPoint anchorPoint;
隱式動(dòng)畫
- 每一個(gè)UIView內(nèi)部都默認(rèn)關(guān)聯(lián)著一個(gè)CALayer鹉究,我們可用稱這個(gè)Layer為Root Layer(根層)
- 所有的非Root Layer,也就是手動(dòng)創(chuàng)建的CALayer對(duì)象踪宠,都存在著隱式動(dòng)畫
什么是隱式動(dòng)畫自赔?
當(dāng)對(duì)非Root Layer的部分屬性進(jìn)行修改時(shí),默認(rèn)會(huì)自動(dòng)產(chǎn)生一些動(dòng)畫效果
而這些屬性稱為Animatable Properties(可動(dòng)畫屬性)-
列舉幾個(gè)常見的Animatable Properties:
bounds:用于設(shè)置CALayer的寬度和高度柳琢。修改這個(gè)屬性會(huì)產(chǎn)生縮放動(dòng)畫
backgroundColor:用于設(shè)置CALayer的背景色绍妨。修改這個(gè)屬性會(huì)產(chǎn)生背景色的漸變動(dòng)畫
position:用于設(shè)置CALayer的位置。修改這個(gè)屬性會(huì)產(chǎn)生平移動(dòng)畫
- (void)viewDidLoad { [super viewDidLoad]; CALayer *layer = [CALayer layer]; layer.position = CGPointMake(100, 100); layer.bounds = CGRectMake(0, 0, 100, 100); layer.backgroundColor = [UIColor redColor].CGColor; self.layer = layer; [self.view.layer addSublayer:layer]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ /*想要關(guān)閉隱式動(dòng)畫,首先要了解核心動(dòng)畫的原理 任何動(dòng)畫,它都會(huì)封裝到一個(gè)事務(wù)里面.學(xué)數(shù)據(jù)庫都應(yīng)該了解事務(wù)的吧. 什么叫事務(wù), 把很多操作綁定在一起, 必須這些操作中的每一項(xiàng)全部完成,它才能做一些事件. 就是說,你一個(gè)動(dòng)畫全部執(zhí)行完之后,它才能執(zhí)行一些事件. 動(dòng)畫的底層都是包裝到一個(gè)事務(wù)里面. */ //開啟一個(gè)事務(wù) [CATransaction begin]; //不需要隱式動(dòng)畫 //[CATransaction setDisableActions:YES]; //隨機(jī)改變位置 self.layer.position = CGPointMake(arc4random_uniform(400), arc4random_uniform(400)); //隨機(jī)改變大小 self.layer.bounds = CGRectMake(0, 0, arc4random_uniform(200), arc4random_uniform(200)); //隨機(jī)改變圓角 self.layer.cornerRadius = arc4random_uniform(50); //隨機(jī)改變顏色 self.layer.backgroundColor = [self randomColor].CGColor; [CATransaction commit]; //還可以設(shè)置隱式動(dòng)畫執(zhí)行的時(shí)長 [CATransaction setAnimationDuration:3.0]; /* 總結(jié): 1.只有非根層才有隱式動(dòng)畫 2.只要一個(gè)屬性有Animatable屬性,它就會(huì)有隱式動(dòng)畫 */ } #pragma mark 返回隨機(jī)顏色 - (UIColor *)randomColor{ CGFloat r = arc4random_uniform(256) / 255.0; CGFloat g = arc4random_uniform(256) / 255.0; CGFloat b = arc4random_uniform(256) / 255.0; return [UIColor colorWithRed:r green:g blue:b alpha:1]; }