iOS CALayer 學(xué)習(xí)

CALayer簡介

CALayer主要是展示內(nèi)容和動(dòng)畫操作,CALayer不包含在UIKit中,不能響應(yīng)事件,由于CALayer在設(shè)計(jì)之初就考慮它的動(dòng)畫操作功能,CALayer很多屬性在修改時(shí)都能形成動(dòng)畫效果,這種屬性稱為“隱式動(dòng)畫屬性”。對于UIView的根圖層而言屬性的修改并不形成動(dòng)畫效果,因?yàn)楹芏嗲闆r下根圖層更多的充當(dāng)容器的做用,如果它的屬性變動(dòng)形成動(dòng)畫效果會(huì)直接影響子圖層。另外,UIView的根圖層創(chuàng)建工作完全由iOS負(fù)責(zé)完成,無法重新創(chuàng)建,但是可以往根圖層中添加子圖層或移除子圖層。

CALayer屬性:

屬性 說明 是否支持隱式動(dòng)畫
anchorPoint 和中心點(diǎn)position重合的一個(gè)點(diǎn),稱為“錨點(diǎn)”,錨點(diǎn)的描述是相對于x、y位置比例而言的默認(rèn)在圖像中心點(diǎn)(0.5,0.5)的位置
backgroundColor 圖層背景顏色
borderColor 邊框顏色
borderWidth 邊框?qū)挾?/td>
bounds 圖層大小
contents 圖層顯示內(nèi)容,例如可以將圖片作為圖層內(nèi)容顯示
contentsRect 圖層顯示內(nèi)容的大小和位置
cornerRadius 圓角半徑
doubleSided 圖層背面是否顯示,默認(rèn)為YES
frame 圖層大小和位置,不支持隱式動(dòng)畫,所以CALayer中很少使用frame,通常使用bounds和position代替
hidden 是否隱藏
mask 圖層蒙版
maskToBounds 子圖層是否剪切圖層邊界,默認(rèn)為NO
opacity 透明度 ,類似于UIView的alpha
position 圖層中心點(diǎn)位置,類似于UIView的center
shadowColor 陰影顏色
shadowOffset 陰影偏移量
shadowOpacity 陰影透明度,注意默認(rèn)為0,如果設(shè)置陰影必須設(shè)置此屬性
shadowPath 陰影的形狀
shadowRadius 陰影模糊半徑
sublayers 子圖層
sublayerTransform 子圖層形變
transform 圖層形變

-CALayer中透明度使用opacity而不是我們平常使用的alpha,中心點(diǎn)使用position而不是center </br>
-CALayer中很少使用frame屬性,frame屬性不支持動(dòng)畫,可以用bounds、position代替 </br>
-anchorPoint圖層的錨點(diǎn),范圍在(01,01)表示在x、y軸的比例,這個(gè)點(diǎn)永遠(yuǎn)可以同position(中心點(diǎn))重合,當(dāng)圖層中心點(diǎn)固定后,調(diào)整anchorPoint即可達(dá)到調(diào)整圖層顯示位置的作用(因?yàn)樗肋h(yuǎn)和position重合)</br>

CALayer繪圖

UIView中drawRect方法繪制圖形、圖像,本質(zhì)是在圖層中繪制。而這里介紹如何直接在圖層中繪制。在圖層中繪圖基本沒有什么區(qū)別,只是drawRect方法是由UIKit組件進(jìn)行調(diào)用,因此可以調(diào)用一些UIKit封裝的方法進(jìn)行繪圖,而直接繪制到圖層的方法只能用原生的Core Graphics方法繪制。

圖層繪圖有兩種方法,不管使用哪種方法都要調(diào)用setNeedsDisplay(UIView和CALayer都有setNeedsDisplay方法, 而這里調(diào)用的是圖層的方法)</br>

1、定義圖層繪制

// 繼承CALayer 實(shí)現(xiàn)方法
- (void)drawInContext:(CGContextRef)ctx {
}

2、圖層代理繪制

// CALayerDelegate 代理方法
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
}

使用定義圖層繪制

在自定義圖層時(shí),需要繼承CALayer創(chuàng)建文件,在.m文件中實(shí)現(xiàn)-(void)drawInContext:(CGContextRef)ctx {},顯示圖層中繪制的內(nèi)容也要調(diào)用圖層的setNeedDisplay方法,否則drawInContext方法將不會(huì)調(diào)用。

#import "MyCALayer.h"
#import <UIKit/UIKit.h>

@implementation MyCALayer

- (void)drawInContext:(CGContextRef)ctx {
    CGContextSaveGState(ctx);
    
    //圖形上下文形變,解決圖片倒立的問題
    CGContextScaleCTM(ctx, 1, -1);
    CGContextTranslateCTM(ctx, 0, -100);
    
    UIImage *image = [UIImage imageNamed:@"vehicleResource.png"];
    
    //注意這個(gè)位置是相對于圖層而言的不是屏幕
    CGContextDrawImage(ctx, CGRectMake(0, 0, 100, 100), image.CGImage);
    
    CGContextRestoreGState(ctx);
}

@end

#import "ViewController.h"
#import "MyCALayer.h"

@interface ViewController ()

@property (nonatomic, strong) MyCALayer *myCALayer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    UIView  *showView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
    
    self.myCALayer = [[MyCALayer alloc] init];
    
    self.myCALayer.bounds = CGRectMake(0, 0, 100, 100);
    
    self.myCALayer.position = CGPointMake(50, 50);
    
    [showView.layer addSublayer:self.myCALayer];
    
    showView.backgroundColor = [UIColor redColor];
    
    [self.view addSubview:showView];
    
    [self.myCALayer setNeedsDisplay];
    
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end

圖2.png

使用圖層代理繪制

首先設(shè)置圖層代理,實(shí)現(xiàn)代理協(xié)議方法- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx,設(shè)置完代理后必須要調(diào)用圖層的setNeedDisplay方法,否則繪制的內(nèi)容無法顯示。

#import "ViewController.h"

@interface ViewController () <CALayerDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    UIView  *showView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
    // 設(shè)置背景
    showView.layer.backgroundColor = [UIColor redColor].CGColor;
    //注意僅僅設(shè)置圓角,對于圖形而言可以正常顯示,但是對于圖層中繪制的圖片無法正確顯示
    //如果想要正確顯示則必須設(shè)置masksToBounds=YES,剪切子圖層
    showView.layer.cornerRadius = 50;
    showView.layer.masksToBounds = YES;
//陰影效果無法和masksToBounds同時(shí)使用,因?yàn)閙asksToBounds的目的就是剪切外邊框,
//設(shè)置陰影  顏色 偏移量 透明度
//    showView.layer.shadowColor = [UIColor grayColor].CGColor;
//    showView.layer.shadowOffset = CGSizeMake(2, 2);
//    showView.layer.shadowOpacity = 1;
    //設(shè)置邊框 顏色 寬度
    showView.layer.borderColor = [UIColor whiteColor].CGColor;
    showView.layer.borderWidth = 2;
    //設(shè)置圖層代理
    showView.layer.delegate = self;
    
    [self.view addSubview:showView];
#warning 必須調(diào)用 不然無法繪制
    [showView.layer setNeedsDisplay];
}

/**
  繪制圖形、圖像到圖層,注意參數(shù)中的ctx是圖層的圖形上下文,其中繪圖位置也是相對圖層而言的

 @param layer 圖層
 @param ctx 圖形上下文
 */
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
    CGContextSaveGState(ctx);
    
    //圖形上下文形變,解決圖片倒立的問題
    CGContextScaleCTM(ctx, 1, -1);
    CGContextTranslateCTM(ctx, 0, -100);
    
    UIImage *image = [UIImage imageNamed:@"vehicleResource.png"];
    
    //注意這個(gè)位置是相對于圖層而言的不是屏幕
    CGContextDrawImage(ctx, CGRectMake(0, 0, 100, 100), image.CGImage);
    
    CGContextRestoreGState(ctx);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end

圖1.png

使用代理方法繪制圖形、圖像時(shí),通過- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx方法獲取圖形上下文,圖形上下文指的當(dāng)前圖層的上下文,繪圖中的位置是相對于當(dāng)前圖層而言的。

在上述代碼中masksToBounds不設(shè)置是無法顯示圓形效果,但是對于其他圖形沒有這個(gè)限制,是因?yàn)槔L制一張圖片到圖層上的時(shí)候會(huì)重新創(chuàng)建一個(gè)圖層添加到當(dāng)前圖層,設(shè)置圓角的圖層是底圖層,子圖層還是矩形,只有設(shè)置了masksToBounds為YES讓子圖層按底圖層剪切才能顯示圓角效果。

如果我們同時(shí)需要圓形圖像又要陰影效果,我們只需要在添加一個(gè)圖層就能完美解決,只要把陰影圖層放在繪制圖形的下一層就好。我們在使用Core Graphics繪制圖片時(shí)會(huì)倒立顯示,對圖層的圖形上下文進(jìn)行了反轉(zhuǎn)。其實(shí)可以控制圖層直接旋轉(zhuǎn)而不用借助于圖形上下文的形變操作,只需要設(shè)置圖層的transform屬性即可。需要注意的是transform是CATransform3D類型,形變可以在三個(gè)維度上進(jìn)行。

形變對于動(dòng)畫有特殊的意義。在動(dòng)畫開發(fā)中形變往往不是直接設(shè)置transform,而是通過keyPath進(jìn)行設(shè)置。這種方法設(shè)置形變的本質(zhì)和前面沒有區(qū)別,只是利用了KVC可以動(dòng)態(tài)修改其屬性值而已,但是這種方式在動(dòng)畫中確實(shí)很常用的,因?yàn)樗梢院芊奖愕膶追N形變組合到一起使用。同樣是解決動(dòng)畫旋轉(zhuǎn)問題,只要將前面的旋轉(zhuǎn)代碼改為下面的代碼即可:

[layer setValue:@M_PI forKeyPath:@"transform.rotation.x"];

當(dāng)然,通過key path設(shè)置形變參數(shù)就需要了解有哪些key path可以設(shè)置.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,807評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內(nèi)容