出處:小碼哥大神班5期
CALayer的基本操作
1.CALayer的簡介
CALayer又稱做層档叔,每個(gè)view內(nèi)部都有一個(gè)layer這樣的屬性藻烤。UIView因?yàn)镃ALayer層统刮,才具有顯示功能表牢。我們可以通過操作CALayer對(duì)象,對(duì)UIView進(jìn)行一些外觀屬性的調(diào)整沐悦。比如設(shè)置陰影成洗、圓角、邊框等所踊。
2.操作layer改變UIView的外觀
//設(shè)置圓角
view.layer.cornerRadius = 5;
//設(shè)置陰影不透明度泌枪,默認(rèn)圖層是有陰影的,只不過是透明的
view.layer.shadowOpacity = 1;
//設(shè)置陰影圓角
view.layer.shadowRadius = 10;
//設(shè)置陰影顏色
view.layer.shadowColor = [UIColor grayColor].CGColor;
//設(shè)置陰影位置的偏移量
view.layer.shadowOffset = CGSizeMake(10, 10);
//設(shè)置邊框
view.layer.borderWidth = 2;
view.layer.borderColor = [UIColor blackColor].CGColor;
效果:
3.操作layer改變UIImageViewView的外觀
//設(shè)置圖片邊框
imageV.layer.borderWidth = 2;
imageV.layer.borderColor = [UIColor orangeColor].CGColor;
//設(shè)置圖片圓角半徑
imageV.layer.cornerRadius = 100;
//裁剪超出區(qū)域部分的的圖片
imageV.layer.masksToBounds = YES;
/*
注:UIImageView當(dāng)中的ImageView并不是直接添加在層上面的碌燕,這是添加在layer當(dāng)中的
contents里,我們?cè)O(shè)置所有屬性只作用在層上面继薛,對(duì)contents里面的東西并不起作用修壕,所有以我們
看不到圖片有圓角的效果,可以把maskToBounds這個(gè)屬性設(shè)為yes遏考,
當(dāng)設(shè)為yes慈鸠,就會(huì)把超過根層以外的東西都給裁剪掉。
*/
效果:
4.layer的CATransform3D屬性
只有旋轉(zhuǎn)的時(shí)候才可以看出3d效果
可以通過kvc的方式進(jìn)行設(shè)置屬性灌具,
但是CATransform3DMakeRotation的值是一個(gè)結(jié)構(gòu)體青团,所以用kvc進(jìn)行設(shè)置時(shí)要把結(jié)構(gòu)體轉(zhuǎn)成對(duì)象
NSValue *value = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 1, 0, 0)];
[_imageView.layer setValue:value forKeyPath:@"transform.scale"];
什么時(shí)候用kvc
- 當(dāng)需要做一些快速縮放,平移咖楣,二維的旋轉(zhuǎn)是用kvc.
后面forKeyPath屬性值不是亂寫的督笆,蘋果文檔當(dāng)中給了相關(guān)的屬性。
//平移
[UIView animateWithDuration:1 animations:^{
self.imageV.layer.transform = CATransform3DMakeTranslation(-50, -100, 1);
}];
//縮放
[UIView animateWithDuration:1 animations:^{
[self.imageV.layer setValue:@(0.5) forKeyPath:@"transform.scale"];
}];
//旋轉(zhuǎn)
[UIView animateWithDuration:1 animations:^{
self.imageV.layer.transform =CATransform3DMakeRotation(M_PI , 1, 0, 0);
}];
效果:
自定義CALayer
1.如何自定義layer
自定義CALayer的方式和創(chuàng)建UIView的方式非常相似诱贿。
CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(50, 50, 100, 100);
layer.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:layer];
//給layer設(shè)置圖片
layer.contents = (id)[UIImage imageNamed:@"阿貍頭像"].CGImage;
2.關(guān)于CALayer的疑惑
- 為什么要使用CGImageRef娃肿、CGColorRef
為了保證可移植性咕缎,QuartzCore不能使用UIImage、UIColor只能使用CGImageRef料扰、CGColorRef
- UIView和CALayer都能夠顯示圖形凭豪,該怎么選擇?
對(duì)比CALayer晒杈,UIView多了一個(gè)事件處理功能嫂伞。也就是說CALayer不能處理用戶的觸摸事件,而UIView可以桐智。所以如果顯示的東西需要跟用戶進(jìn)行交互的話末早,用UIView烟馅;如果不需要的話用CALayer说庭;因?yàn)镃ALayer的性能會(huì)高一些,因此它少了事件處理功能郑趁,更加輕量級(jí)刊驴。
3.position和anchorpoint
position和anchorpoint是CALayer的兩個(gè)屬性。
以前修改一個(gè)空間的位置都是通過frame的方式進(jìn)行修改」讶螅現(xiàn)在利用CALayer的position和anchorpoint也能夠修改控件的位置
position:它是用來設(shè)置當(dāng)前的layer在父控件當(dāng)中的位置的.所以它的坐標(biāo)原點(diǎn)是以父控件的左上角為坐標(biāo)原點(diǎn)捆憎; anchorpoint:它是決定CALayer身上哪一個(gè)會(huì)在position屬性所指的位置,anchorpoint是以當(dāng)前的layer左上角為原點(diǎn)梭纹;它的取值范圍是0~1躲惰,默認(rèn)值是(0.5,0.5)的位置变抽,anchorpoint又稱錨點(diǎn)础拨,就是把錨點(diǎn)定到position所指的位置
兩者結(jié)合使用:想要修改某個(gè)控件的位置,可以先設(shè)置它的position點(diǎn)绍载,設(shè)置完畢后诡宗,在設(shè)置layer身上的anchorpoint錨點(diǎn)。
4.隱式動(dòng)畫
- 什么是隱式動(dòng)畫
了解什么是隱式動(dòng)畫之前击儡,要先了解什么是根曾和非根層塔沃。
根層:UIView內(nèi)部自動(dòng)關(guān)聯(lián)著的那個(gè)layer,我們稱著為根層阳谍。
非根層:自己手動(dòng)創(chuàng)建的層蛀柴,稱著為非根層。
隱式動(dòng)畫就是當(dāng)非根層的部分屬性進(jìn)行修改時(shí)矫夯,自動(dòng)產(chǎn)生的一些動(dòng)畫效果鸽疾。
- 如何取消隱式動(dòng)畫?
首先要了解動(dòng)畫底層是怎么做的茧痒,動(dòng)畫的底層是包裝成一個(gè)事物來進(jìn)行的肮韧。
什么是事務(wù)?
很多操作綁定在一起,當(dāng)這些操作執(zhí)行完畢后弄企,才去執(zhí)行下一個(gè)操作超燃。
//開啟事務(wù)
[CATransaction begin];
//設(shè)置事務(wù)沒有動(dòng)畫
[CATransaction setDisableActions:yes];
//設(shè)置動(dòng)畫執(zhí)行時(shí)長
[CATransaction setAnimationDuration:2];
//提交事務(wù)
[CATransaction commit];
6.CABasicAnimation基礎(chǔ)核心動(dòng)畫
核心動(dòng)畫是作用在層上面的。
動(dòng)畫的本質(zhì)是改變圖層的某一個(gè)屬性拘领。
CABasicAnimation *anim = [CABasicAnimation animation];
圖層有哪些屬性意乓,這里才能寫哪些屬性。
anim.keyPath = @"transform.scale";
anim.toValue = @0.5;
//告訴動(dòng)畫完成時(shí)不要移除
anim.removedOnCompletion = NO;
//保存動(dòng)畫最前面的效果
anim.fillMode = kCAFillModeForwards;
//把動(dòng)畫添加到層上面
[view.layer addAnimation:anim forkey:nil];
7.UIView與核心動(dòng)畫的對(duì)比
- UIView和核心動(dòng)畫的區(qū)別
核心動(dòng)畫只能添加到CALayer
核心動(dòng)畫一切都是假象约素,并不會(huì)改變真實(shí)的值届良。
- 什么時(shí)候使用UIView動(dòng)畫
如果需要與用戶交互就使用UIView動(dòng)畫。
不需要就使用核心動(dòng)畫
- 什么場景使用核心動(dòng)畫最多
在轉(zhuǎn)場動(dòng)畫中圣猎,核心動(dòng)畫的類型比較多士葫。
根據(jù)一個(gè)路徑做動(dòng)畫,只能用核心動(dòng)畫(幀動(dòng)畫)
動(dòng)畫組:同時(shí)做多個(gè)動(dòng)畫
練習(xí)項(xiàng)目
時(shí)鐘效果
代碼:
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *clockView;
//秒針的層
@property (weak,nonatomic) CALayer *secondLayer;
//分針的層
@property (weak,nonatomic) CALayer *minuteLayer;
//時(shí)針的層
@property (weak,nonatomic) CALayer *hourLayer;
@end
@implementation ViewController
//每一秒轉(zhuǎn)的度數(shù)
#define secondA 6
//每一分轉(zhuǎn)的度數(shù)
#define minuteA 6
//每一小時(shí)要轉(zhuǎn)的度數(shù)
#define hourA 30
//角度轉(zhuǎn)弧度
#define angleRad(angle) ((angle)/180 * M_PI)
- (void)viewDidLoad {
[super viewDidLoad];
//每一秒轉(zhuǎn)6度送悔,獲取當(dāng)前多少秒*6得到要轉(zhuǎn)的角度
//添加秒針
self.secondLayer = [self addShiZhenWithHeight:80 width:1 color:[UIColor redColor]];
//添加分針
self.minuteLayer = [self addShiZhenWithHeight:70 width:3 color:[UIColor blackColor]];
//添加時(shí)針
self.hourLayer = [self addShiZhenWithHeight:50 width:4 color:[UIColor blackColor]];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
[self timeChange];
}
//添加時(shí)針
- (CALayer *)addShiZhenWithHeight:(CGFloat)height width : (CGFloat)width color:(UIColor *)color
{
//實(shí)例化一個(gè)層
CALayer *layer = [[CALayer alloc] init];
//設(shè)置層的大小
layer.frame = CGRectMake(self.clockView.frame.size.width * 0.5, self.clockView.frame.size.height * 0.5, width, height);
//設(shè)置層的背景顏色
layer.backgroundColor = color.CGColor;
//設(shè)置層的位置
layer.position = CGPointMake(self.clockView.frame.size.width * 0.5, self.clockView.frame.size.height * 0.5);
layer.anchorPoint = CGPointMake(0.5, 1);
// layer.transform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
//添加到父層
[self.clockView.layer addSublayer:layer];
return layer;
}
- (void)timeChange
{
//獲取系統(tǒng)日歷
NSCalendar * calendar = [NSCalendar currentCalendar];
//components:日歷單元:年慢显,月,日欠啤,時(shí)荚藻,分,秒
//fromDate:當(dāng)前的日期
//- (NSDateComponents *)components:(NSCalendarUnit)unitFlags fromDate:(NSDate *)date;
NSDateComponents *cmp = [calendar components:NSCalendarUnitSecond|NSCalendarUnitMinute|NSCalendarUnitHour fromDate:[NSDate date]];
//獲取當(dāng)前是多少秒
NSInteger curSecond = cmp.second;
//秒針要轉(zhuǎn)的度數(shù)
CGFloat curSecondA = curSecond*secondA;
self.secondLayer.transform = CATransform3DMakeRotation(angleRad(curSecondA), 0, 0, 1);
//獲取當(dāng)前是多少分
NSInteger curMinute = cmp.minute;
//分針要轉(zhuǎn)的度數(shù)
CGFloat curMinuteA = curMinute * minuteA;
self.minuteLayer.transform = CATransform3DMakeRotation(angleRad(curMinuteA), 0, 0, 1);
//獲取當(dāng)前是幾時(shí)
NSInteger curHour = cmp.hour;
//時(shí)針要轉(zhuǎn)的度數(shù)+每改變一分時(shí)針要轉(zhuǎn)0.5度
CGFloat curHourA = curHour * hourA + curMinute * 0.5;
self.hourLayer.transform = CATransform3DMakeRotation(angleRad(curHourA), 0, 0, 1);
}