Core Animation 學(xué)習(xí)記錄

CALayer簡介####

The CALayer class manages image-based content and allows you to perform animations on that content. Layers are often used to provide the backing store for views but can also be used without a view to display content. A layer’s main job is to manage the visual content that you provide but the layer itself has visual attributes that can be set, such as a background color, border, and shadow. In addition to managing visual content, the layer also maintains information about the geometry of its content (such as its position, size, and transform) that is used to present that content onscreen. Modifying the properties of the layer is how you initiate animations on the layer’s content or geometry. A layer object encapsulates the duration and pacing of a layer and its animations by adopting the CAMediaTiming protocol, which defines the layer’s timing information.

If the layer object was created by a view, the view typically assigns itself as the layer’s delegate automatically, and you should not change that relationship. For layers you create yourself, you can assign a delegate object and use that object to provide the contents of the layer dynamically and perform other tasks. A layer may also have a layout manager object (assigned to the layoutManager property) to manage the layout of subviews separately.

這是官方文檔對(duì)CALayer的解釋,個(gè)人理解CALayer是用來繪制泼橘、渲染
圖形的耘柱。我們利用drawRect:方法繪圖的本質(zhì)就是繪制到了UIView的layer上。

與UIView又有什么區(qū)別和聯(lián)系呢幕随?####

事實(shí)上使用Quartz 2D繪圖時(shí)其實(shí)是在操作CALayer,UIView 下有個(gè)屬性layer;這個(gè)layer層就是真正繪制UIView所要展示的東西渊跋。然而之所以要將CALayer封裝成UIView則是為了給其添加事件響應(yīng)租幕。

因?yàn)镃ALayer是繼承與NSObject的囊蓝,所以他是不具備響應(yīng)的。而UIView是繼承與UIResponder的令蛉,UIResponder本身可以提供事件響應(yīng)聚霜,再用CALayer給他繪制一個(gè)圖像,那一個(gè)具有響應(yīng)事件的對(duì)象就誕生了珠叔,他就是我們的UIView蝎宇。

當(dāng)我們創(chuàng)建一個(gè)UIView對(duì)象時(shí),系統(tǒng)自動(dòng)為我們創(chuàng)建一個(gè)CALayer對(duì)象,這個(gè)對(duì)象就是UIView的layer屬性祷安。

CALayer常用屬性####

屬性 說明 是否支持隱式動(dòng)畫
anchorPoint 和中心點(diǎn)position重合的一個(gè)點(diǎn)姥芥,稱為“錨點(diǎn)”,錨點(diǎn)的描述是相對(duì)于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)位置咱娶,左上角的位置
shadowColor 陰影顏色
shadowOffset 陰影偏移量
shadowOpacity 陰影透明度,注意默認(rèn)為0强品,如果設(shè)置陰影必須設(shè)置此屬性
shadowPath 陰影的形狀
shadowRadius 陰影模糊半徑
sublayers 子圖層
sublayerTransform 子圖層形變
transform 圖層形變
  • 隱式屬性動(dòng)畫的本質(zhì)是這些屬性的變動(dòng)默認(rèn)隱含了CABasicAnimation動(dòng)畫實(shí)現(xiàn)節(jié)膘侮。
  • 在CALayer中很少使用frame屬性,因?yàn)閒rame本身不支持動(dòng)畫效果的榛,通常使用bounds和position代替琼了。
  • CALayer中透明度使用opacity表示而不是alpha;中心點(diǎn)使用position表示而不是center夫晌。
  • 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重合)

為了進(jìn)一步說明anchorPoint的作用要糊,假設(shè)有一個(gè)層大小100*100纲熏,現(xiàn)在中心點(diǎn)位置(50,50),由此可以得出frame(0,0,100,100)锄俄。上面說過anchorPoint默認(rèn)為(0.5,0.5)局劲,同中心點(diǎn)position重合,此時(shí)使用圖形描述如圖1奶赠;當(dāng)修改anchorPoint為(0,0)鱼填,此時(shí)錨點(diǎn)處于圖層左上角,但是中心點(diǎn)poition并不會(huì)改變毅戈,因此圖層會(huì)向右下角移動(dòng)苹丸,如圖2;然后修改anchorPoint為(1,1,)苇经,position還是保持位置不變赘理,錨點(diǎn)處于圖層右下角,此時(shí)圖層如下圖扇单。

屏幕快照 2017-01-13 下午1.41.30.png
#import "ViewController.h"

#define WIDTH 50

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self drawMyLayer];
}

//繪制圖層
- (void)drawMyLayer{
    CGSize size = [UIScreen mainScreen].bounds.size;
    
    //獲取根視圖
    CALayer * layer = [[CALayer alloc]init];
    
    //設(shè)置背景顏色商模,由于QuartzCore是跨平臺(tái)框架 無法直接使用UIColor
    layer.backgroundColor = [UIColor colorWithRed:0 green:146/255 blue:1.0 alpha:1.0].CGColor;
    
    //設(shè)置中心點(diǎn)
    layer.position = CGPointMake(size.width/2, size.height/2);
    
    //設(shè)置大小
    layer.bounds = CGRectMake(0, 0, WIDTH, WIDTH);
    
    //設(shè)置圓角
    layer.cornerRadius = WIDTH/2;
    
    /**設(shè)置陰影*/
    //設(shè)置陰影顏色
    layer.shadowColor = [UIColor redColor].CGColor;
    //設(shè)置陰影偏移量
    layer.shadowOffset = CGSizeMake(2, 2);
    //設(shè)置陰影透明度
    layer.shadowOpacity = 0.9;
    
    /**設(shè)置邊框*/
    //設(shè)置邊框顏色
    layer.borderColor = [UIColor whiteColor].CGColor;
    //設(shè)置邊框?qū)挾?    layer.borderWidth = 1;
    
    //設(shè)置錨點(diǎn)
    layer.anchorPoint = CGPointZero;
    
    [self.view.layer addSublayer:layer];
    
}

//點(diǎn)擊放大
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    UITouch * touch = [touches anyObject];
    CALayer * layer = [self.view.layer.sublayers lastObject];
    layer.backgroundColor = [UIColor greenColor].CGColor;
//    CGFloat width = layer.bounds.size.width;
//    if(width == WIDTH){
//        width = WIDTH * 4;
//    }else{
//        width = WIDTH;
//    }
//    layer.bounds = CGRectMake(0, 0, width, width);
    //函數(shù)返回一個(gè)CGPoint類型的值,表示觸摸在view這個(gè)視圖上的位置,這里返回的位置是針對(duì)view的坐標(biāo)系的施流。調(diào)用時(shí)傳入的view參數(shù)為空的話响疚,返回的時(shí)觸摸點(diǎn)在整個(gè)窗口的位置。
    layer.position = [touch locationInView:self.view];
    NSLog(@"%f %f",[touch locationInView:self.view].x,[touch locationInView:self.view].y);
//    layer.cornerRadius = width/2;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
gif1.gif

CALayer繪圖####

圖層繪圖有兩種方法瞪醋,不管使用哪種方法繪制完必須調(diào)用圖層的setNeedDisplay方法(注意是圖層的方法忿晕,不是UIView的方法,前面我們介紹過UIView也有此方法)

  • 通過圖層代理drawLayer: inContext:方法繪制
  • 通過自定義圖層drawInContext:方法繪制
使用代理方法繪圖#####

通過代理方法進(jìn)行圖層繪圖只要指定圖層的代理趟章,然后在代理對(duì)象中重寫*-(void)drawLayer:(CALayer )layer inContext:(CGContextRef)ctx方法即可杏糙。需要注意這個(gè)方法雖然是代理方法但是不用手動(dòng)實(shí)現(xiàn)CALayerDelegate慎王,因?yàn)镃ALayer定義中給NSObject做了分類擴(kuò)展蚓土,所有的NSObject都包含這個(gè)方法。另外設(shè)置完代理后必須要調(diào)用圖層的setNeedDisplay方法赖淤,否則繪制的內(nèi)容無法顯示蜀漆。

Demo1 繪制一個(gè)圓形圖層######
#import "ViewController.h"

#define PHONE_HEIGHT 150

//角度轉(zhuǎn)弧度
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)

@interface ViewController ()<CALayerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    //自定義圖層
    CALayer * layer = [[CALayer alloc]init];
    //設(shè)置圖層的大小位置
    layer.bounds = CGRectMake(0, 0, PHONE_HEIGHT, PHONE_HEIGHT);
    //設(shè)置圖層原點(diǎn)的位置
    layer.position = CGPointMake(160, 200);
    //設(shè)置圖層的背景顏色
    layer.backgroundColor = [UIColor redColor].CGColor;
    //設(shè)置圓角
    layer.cornerRadius = PHONE_HEIGHT/2;
    //注意僅僅設(shè)置圓角,對(duì)于圖形而言可以正常顯示咱旱,但是對(duì)于圖層中繪制的圖片無法正確顯示
    //如果想要正確顯示則必須設(shè)置masksToBounds=YES确丢,剪切子圖層
    layer.masksToBounds = YES;
    //陰影效果無法和masksToBounds同時(shí)使用,因?yàn)閙asksToBounds的目的就是剪切外邊框吐限,
    //而陰影效果剛好在外邊框
    //    layer.shadowColor=[UIColor grayColor].CGColor;
    //    layer.shadowOffset=CGSizeMake(2, 2);
    //    layer.shadowOpacity=1;
    //設(shè)置邊框
    layer.borderColor = [UIColor whiteColor].CGColor;
    layer.borderWidth = 2;
    
    //設(shè)置圖層代理
    layer.delegate = self;
    
    //調(diào)用圖層setNeedDisplay 否則代理方法不會(huì)調(diào)用
    [layer setNeedsDisplay];
    
    //添加圖層到根圖層
    [self.view.layer addSublayer:layer];
    
    
}

#pragma mark 繪制圖形鲜侥、圖像到圖層,注意參數(shù)中的ctx是圖層的圖形上下文诸典,其中繪圖位置也是相對(duì)圖層而言的
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
    //這個(gè)圖層是上面定義的圖層
    CGContextSaveGState(ctx);
    //CGContextScaleCTM 縮放函數(shù)
    //CGContextTranslateCTM 移動(dòng)函數(shù)
    //CGContextRotateCTM 旋轉(zhuǎn)加翻轉(zhuǎn)函數(shù)
    
    //圖像上下文形變 解決圖片倒立的問題
    /*
        CGContextScaleCTM(ctx, 1, -1);
        CGContextTranslateCTM(ctx, 0, -PHONE_HEIGHT);
     */
    
    //圖片旋轉(zhuǎn)90度并翻轉(zhuǎn)
    /*
        CGContextTranslateCTM(ctx, PHONE_HEIGHT, 0);
        CGContextRotateCTM(ctx,DEGREES_TO_RADIANS(90));
     */

    UIImage * image = [UIImage imageNamed:@"4444.png"];
    
    //注意這個(gè)位置是相對(duì)于圖層而言的不是屏幕
    CGContextDrawImage(ctx, CGRectMake(0, 0, PHONE_HEIGHT, PHONE_HEIGHT), image.CGImage);
    
    CGContextRestoreGState(ctx);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

如果不做任何操作是圖片是倒立的如圖2描函,設(shè)置縮放和移動(dòng)位置使其正立如圖1,設(shè)置旋轉(zhuǎn)90度如圖3

屏幕快照 2017-01-17 下午6.25.13.png
Demo2 繪制一個(gè)帶有陰影圓形圖層######

如果設(shè)置了masksToBounds=YES之后確實(shí)可以顯示圖片圓角效果狐粱,但遺憾的是設(shè)置了這個(gè)屬性之后就無法設(shè)置陰影效果舀寓。因?yàn)閙asksToBounds=YES就意味著外邊框不能顯示,而陰影恰恰作為外邊框繪制的肌蜻,這樣兩個(gè)設(shè)置就產(chǎn)生了矛盾互墓。要解決這個(gè)問題不妨換個(gè)思路:使用兩個(gè)大小一樣的圖層,下面的圖層負(fù)責(zé)繪制陰影蒋搜,上面的圖層用來顯示圖片篡撵。

#import "ViewController.h"

#define PHONE_HEIGHT 150

//角度轉(zhuǎn)弧度
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)

@interface ViewController ()<CALayerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    //圖層中心點(diǎn)
    CGPoint position = CGPointMake(160, 200);
    //設(shè)置圖層大小
    CGRect bounds = CGRectMake(0, 0, PHONE_HEIGHT, PHONE_HEIGHT);
    //設(shè)置半徑
    CGFloat cornerRadius = PHONE_HEIGHT/2;
    //設(shè)置邊框?qū)挾?    CGFloat borderWidth = 2;
    
    //陰影圖層
    CALayer * layerShadow = [[CALayer alloc]init];
    layerShadow.bounds = bounds;
    layerShadow.position = position;
    layerShadow.cornerRadius = cornerRadius;
    //設(shè)置陰影的顏色、偏移量豆挽、陰影透明度
    layerShadow.shadowColor = [UIColor grayColor].CGColor;
    layerShadow.shadowOffset = CGSizeMake(2, 1);
    layerShadow.shadowOpacity = 1;
    //設(shè)置邊框顏色
    layerShadow.borderColor = [UIColor whiteColor].CGColor;
    layerShadow.borderWidth = borderWidth;
    [self.view.layer addSublayer:layerShadow];
    
    //容器圖層
    CALayer * layer = [[CALayer alloc]init];
    layer.bounds = bounds;
    layer.position = position;
    layer.backgroundColor = [UIColor redColor].CGColor;
    layer.cornerRadius = cornerRadius;
    layer.masksToBounds = YES;
    layer.borderColor = [UIColor whiteColor].CGColor;
    layer.borderWidth = borderWidth;
    
    //設(shè)置圖層代理
    layer.delegate = self;
    
    //添加圖層到根視圖
    [self.view.layer addSublayer:layer];
    
    //調(diào)用圖層setNeedDisplay 育谬,否則代理方法不會(huì)被調(diào)用
    [layer setNeedsDisplay];
}

#pragma mark 繪制圖形、圖形到圖層祷杈,注意參數(shù)中的ctx是圖層的圖形上下文 其中繪圖位置也是相對(duì)圖層而言
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
    CGContextSaveGState(ctx);
    
    //圖形上下文形變斑司,解決圖片倒立的問題
    CGContextScaleCTM(ctx, 1, -1);
    CGContextTranslateCTM(ctx, 0, -PHONE_HEIGHT);
    
    UIImage * image = [UIImage imageNamed:@"4444.png"];
    CGContextDrawImage(ctx, CGRectMake(0, 0, PHONE_HEIGHT, PHONE_HEIGHT), image.CGImage);
    
    CGContextRestoreGState(ctx);
}
屏幕快照 2017-02-04 上午11.27.03.png
Demo3 使用性變函數(shù)是圖層翻轉(zhuǎn)######

從上面代碼中大家不難發(fā)現(xiàn)使用Core Graphics繪制圖片時(shí)會(huì)倒立顯示,對(duì)圖層的圖形上下文進(jìn)行了反轉(zhuǎn)。在前一篇文章中也采用了類似的方法去解決這個(gè)問題宿刮,但是在那篇文章中也提到過如果直接讓圖像沿著x軸旋轉(zhuǎn)180度同樣可以達(dá)到正確顯示的目的互站,只是當(dāng)時(shí)的旋轉(zhuǎn)靠圖形上下文還無法繞x軸旋轉(zhuǎn)。今天學(xué)習(xí)了圖層之后僵缺,其實(shí)可以控制圖層直接旋轉(zhuǎn)而不用借助于圖形上下文的形變操作胡桃,而且這么操作起來會(huì)更加簡單和直觀。對(duì)于上面的程序磕潮,只需要設(shè)置圖層的transform屬性即可翠胰。需要注意的是transform是CATransform3D類型,形變可以在三個(gè)維度上進(jìn)行自脯,使用方法和前面介紹的二維形變是類似的之景,而且都有對(duì)應(yīng)的形變?cè)O(shè)置方法(如:CATransform3DMakeTranslation()、CATransform3DMakeScale()膏潮、CATransform3DMakeRotation())锻狗。下面的代碼通過CATransform3DMakeRotation()方法在x軸旋轉(zhuǎn)180度解決倒立問題:

#import "ViewController.h"

#define PHONE_HEIGHT 150

//角度轉(zhuǎn)弧度
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)

@interface ViewController ()<CALayerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    CGPoint position = CGPointMake(160, 200);
    CGRect bounds = CGRectMake(0, 0, PHONE_HEIGHT, PHONE_HEIGHT);
    CGFloat cornerRadius = PHONE_HEIGHT/2;
    CGFloat borderWidth = 2;
    
    //陰影圖層
    CALayer * layerShadow = [[CALayer alloc]init];
    layerShadow.bounds = bounds;
    layerShadow.position = position;
    layerShadow.cornerRadius = cornerRadius;
    layerShadow.shadowColor = [UIColor grayColor].CGColor;
    layerShadow.shadowOffset = CGSizeMake(2, 1);
    layerShadow.shadowOpacity = 1;
    layerShadow.borderColor = [UIColor whiteColor].CGColor;
    layerShadow.borderWidth = borderWidth;
    [self.view.layer addSublayer:layerShadow];
    
    //容器圖層
    CALayer * layer = [[CALayer alloc]init];
    layer.bounds = bounds;
    layer.position = position;
    layer.backgroundColor = [UIColor redColor].CGColor;
    layer.cornerRadius = cornerRadius;
    layer.masksToBounds = YES;
    layer.borderColor = [UIColor whiteColor].CGColor;
    layer.borderWidth = borderWidth;
    
    /*
        ********************************平移變換*********************************
        返回一個(gè)平移變換的transform3D對(duì)象 tx,ty焕参,tz對(duì)應(yīng)x轻纪,y,z軸的平移
        CATransform3D CATransform3DMakeTranslation (CGFloat tx, CGFloat ty, CGFloat tz);
     
        在某個(gè)transform3D變換的基礎(chǔ)上進(jìn)行平移變換叠纷,t是上一個(gè)transform3D刻帚,其他參數(shù)同上
        CATransform3D CATransform3DTranslate (CATransform3D t, CGFloat tx, CGFloat ty, CGFloat tz);
     
     
        ********************************縮放變換*********************************
        x,y涩嚣,z分別對(duì)應(yīng)x軸崇众,y軸,z軸的縮放比例
        CATransform3D CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz);
     
        在一個(gè)transform3D變換的基礎(chǔ)上進(jìn)行縮放變換缓艳,其他參數(shù)同上
        CATransform3D CATransform3DScale (CATransform3D t, CGFloat sx, CGFloat sy, CGFloat sz);
     
     
        ********************************旋轉(zhuǎn)變換*********************************
        angle參數(shù)是旋轉(zhuǎn)的角度校摩,為弧度制 0-2π ,x,y阶淘,z決定了旋轉(zhuǎn)圍繞的中軸衙吩,取值為-1——1之間,例如(1溪窒,0坤塞,0),則是繞x軸旋轉(zhuǎn)(0.5,0.5澈蚌,0)摹芙,則是繞x軸與y軸中間45度為軸旋轉(zhuǎn),依次進(jìn)行計(jì)算
        CATransform3D CATransform3DMakeRotation (CGFloat angle, CGFloat x, CGFloat y, CGFloat z);
        
        在一個(gè)transform3D的基礎(chǔ)上進(jìn)行旋轉(zhuǎn)變換,其他參數(shù)如上
        CATransform3D CATransform3DRotate (CATransform3D t, CGFloat angle, CGFloat x, CGFloat y, CGFloat z);
     
     
        ********************************旋轉(zhuǎn)翻轉(zhuǎn)變換*********************************
        將一個(gè)旋轉(zhuǎn)的效果進(jìn)行翻轉(zhuǎn)
        CATransform3D CATransform3DInvert (CATransform3D t);
     
        NOTE: 
            CATransform3D與CGAffineTransform的轉(zhuǎn)換,CGAffineTransform
            是UIKit框架中一個(gè)用于變換的矩陣宛瞄,其作用與CATransform類似浮禾,只是其
            可以直接作用于View,而不用作用于layer,這兩個(gè)矩陣也可以進(jìn)行轉(zhuǎn)換
     
     */
    //利用圖層形變解決圖像倒立問題
    layer.transform = CATransform3DMakeRotation(M_PI, 1, 0, 0);
    
    //設(shè)置圖層代理
    layer.delegate = self;
    
    //添加圖層到根視圖
    [self.view.layer addSublayer:layer];
    
    //設(shè)置圖層setNeedDisplay盈电,否則代理方法不會(huì)被調(diào)用
    [layer setNeedsDisplay];
}


#pragma mark 繪制圖形蝴簇、圖像到圖層,注意參數(shù)中的ctx時(shí)圖層的圖形上下文匆帚,其中繪圖位置也是相對(duì)圖層而言的
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
    //    NSLog(@"%@",layer);//這個(gè)圖層正是上面定義的圖層
    UIImage *image=[UIImage imageNamed:@"4444.png"];
    //注意這個(gè)位置是相對(duì)于圖層而言的不是屏幕
    CGContextDrawImage(ctx, CGRectMake(0, 0, PHONE_HEIGHT, PHONE_HEIGHT), image.CGImage);
}
Demo4使用自定義圖層繪圖######

在自定義圖層中繪圖時(shí)只要自己編寫一個(gè)類繼承于CALayer然后在drawInContext:中繪圖即可熬词。同前面在代理方法繪圖一樣,要顯示圖層中繪制的內(nèi)容也要調(diào)用圖層的setNeedDisplay方法吸重,否則drawInContext方法將不會(huì)調(diào)用互拾。
前面的文章中曾經(jīng)說過,在使用Quartz 2D在UIView中繪制圖形的本質(zhì)也是繪制到圖層中嚎幸,為了說明這個(gè)問題下面演示自定義圖層繪圖時(shí)沒有直接在視圖控制器中調(diào)用自定義圖層颜矿,而是在一個(gè)UIView將自定義圖層添加到UIView的根圖層中(例子中的UIView跟自定義圖層繪圖沒有直接關(guān)系)。從下面的代碼中可以看到:UIView在顯示時(shí)其根圖層會(huì)自動(dòng)創(chuàng)建一個(gè)CGContextRef(CALayer本質(zhì)使用的是位圖上下文)鞭铆,同時(shí)調(diào)用圖層代理(UIView創(chuàng)建圖層會(huì)自動(dòng)設(shè)置圖層代理為其自身)的draw: inContext:方法并將圖形上下文作為參數(shù)傳遞給這個(gè)方法或衡。而在UIView的draw:inContext:方法中會(huì)調(diào)用其drawRect:方法焦影,在drawRect:方法中使用UIGraphicsGetCurrentContext()方法得到的上下文正是前面創(chuàng)建的上下文车遂。

函數(shù) 用法
CGContextRef context = UIGraphicsGetCurrentContext(); 設(shè)置上下文
CGContextMoveToPoint(context, x, y) 開始畫線, x,y 為開始點(diǎn)的坐標(biāo)
CGContextAddLineToPoint(context, x, y) 畫直線, x斯辰,y 為線條結(jié)束點(diǎn)的坐標(biāo)
CGContextAddEllipseInRect(context, rect<CGRect>) 畫橢圓,rect為橢圓的外切矩形
CGContextSetLineCap(context, tap) 設(shè)置線條終點(diǎn)形狀,tap是一個(gè)枚舉變量< kCGLineCapButt 默認(rèn)結(jié)束>舶担、< kCGLineCapRound 圓角>、< kCGLineCapSquare 線頭露出了的樣式>
CGContextSetLineDash(context, phase, lengths, count) //畫虛線,可參考http://blog.csdn.net/zhangao0086/article/details/7234859
CGContextAddRect(context, rect) 畫矩形 ,rect矩形坐標(biāo)大小
CGContextStrokeRect (context, rect) 畫矩形 彬呻,rect矩形坐標(biāo)大小
CGContextStrokeRectWithWidth(context, rect, width) 畫矩形, rect 矩形的坐標(biāo)大小衣陶,width矩形的邊框?qū)挾?/td>
CGContextStrokeLineSegments 一些直線
CGContextAddArc(context, x, y, radius, startAngle, endAngle, clockwise) x,y為圓點(diǎn)坐標(biāo),radius半徑闸氮,startAngle為開始的弧度剪况,endAngle為 結(jié)束的弧度,clockwise 0為順時(shí)針蒲跨,1為逆時(shí)針译断。
CGContextAddArcToPoint(context, x1, y1, x2, y2, radius) 畫弧線,x1,y1跟某點(diǎn)(A)形成一條線的坐標(biāo)p2或悲,x2,y2結(jié)束坐標(biāo)跟某點(diǎn)(A)形成一條線的p3,radius半徑孙咪,得到圓心,設(shè)置內(nèi)切圓弧
CGContextSetShadowWithColor(context, offset,blur, color) 設(shè)置陰影顏色,offset 陰影偏移量巡语,blur透明度翎蹈,color顏色
CGContextSetRGBFillColor(context, red, green, blue ,alpha) 設(shè)置填充顏色,r-g-b ,alpha 透明度
CGContextSetRGBStrokeColor(context, red, green, blue ,alpha) 設(shè)置畫筆顏色,r-g-b ,alpha 透明度
CGContextSetFillColorSpace 空間填充顏色
CGConextSetStrokeColorSpace 設(shè)置畫筆 空間顏色
CGContextFillRect 補(bǔ)充當(dāng)前填充顏色的rect
CGContextSetAlaha 透明度
CGContextTranslateCTM 改變畫布位置
CGContextSetLineWidth 設(shè)置線的寬度
CGContextAddRects 畫多個(gè)線
CGContextAddQuadCurveToPoint 畫曲線
CGContextStrokePath 開始繪制圖片
CGContextDrawPath 設(shè)置繪制模式
CGContextClosePath 封閉當(dāng)前線路
CGContextTranslateCTM(context, 0, rect.size.height); CGContextScaleCTM(context, 1.0, -1.0); 反轉(zhuǎn)畫布
CGContextSetInterpolationQuality 背景內(nèi)置顏色質(zhì)量等級(jí)
CGImageCreateWithImageInRect 從原圖片中取小圖
CGColorGetComponents() 返回顏色的各個(gè)直 以及透明度 可用只讀const float 來接收 是個(gè)數(shù)組
CGContextEOFillPath 使用奇偶規(guī)則填充當(dāng)前路徑
CGContextFillPath 使用非零繞數(shù)規(guī)則填充當(dāng)前路徑
CGContextFillRect 填充指定的矩形
CGContextFillRects 填充指定的一些矩形
CGContextFillEllipseInRect 填充指定矩形中的橢圓
CGContextDrawPath 兩個(gè)參數(shù)決定填充規(guī)則
kCGPathFill 表示用非零繞數(shù)規(guī)則
kCGPathEOFill 表示用奇偶規(guī)則
kCGPathFillStroke 表示填充
kCGPathEOFillStroke 表示描線男公,不是填充
CGContextSetBlendMode 設(shè)置blend mode.
CGContextSaveGState 保存blend mode.
CGContextRestoreGState 在沒有保存之前荤堪,用這個(gè)函數(shù)還原blend mode.

在自定義圖層中繪圖時(shí)只要自己編寫一個(gè)類繼承于CALayer然后在drawInContext:中繪圖即可。同前面在代理方法繪圖一樣,要顯示圖層中繪制的內(nèi)容也要調(diào)用圖層的setNeedDisplay方法澄阳,否則drawInContext方法將不會(huì)調(diào)用曙寡。
前面的文章中曾經(jīng)說過,在使用Quartz 2D在UIView中繪制圖形的本質(zhì)也是繪制到圖層中寇荧,為了說明這個(gè)問題下面演示自定義圖層繪圖時(shí)沒有直接在視圖控制器中調(diào)用自定義圖層举庶,而是在一個(gè)UIView將自定義圖層添加到UIView的根圖層中(例子中的UIView跟自定義圖層繪圖沒有直接關(guān)系)。從下面的代碼中可以看到:UIView在顯示時(shí)其根圖層會(huì)自動(dòng)創(chuàng)建一個(gè)CGContextRef(CALayer本質(zhì)使用的是位圖上下文)揩抡,同時(shí)調(diào)用圖層代理(UIView創(chuàng)建圖層會(huì)自動(dòng)設(shè)置圖層代理為其自身)的draw: inContext:方法并將圖形上下文作為參數(shù)傳遞給這個(gè)方法户侥。而在UIView的draw:inContext:方法中會(huì)調(diào)用其drawRect:方法,在drawRect:方法中使用UIGraphicsGetCurrentContext()方法得到的上下文正是前面創(chuàng)建的上下文峦嗤。

YJSCLayer.m
#import "YJSCLayer.h"

@implementation YJSCLayer

- (void)drawInContext:(CGContextRef)ctx{
    NSLog(@"3-drawInContext:");
    NSLog(@"CGContext:%@",ctx);
    
    CGContextSetRGBFillColor(ctx, 135.0/255.0, 232.0/255.0, 84.0/255.0, 1);
    CGContextSetRGBStrokeColor(ctx, 135.0/255.0, 232.0/255.0, 84.0/255.0, 1);
    CGContextMoveToPoint(ctx, 94.5, 33.5);
    
    CGContextAddLineToPoint(ctx,104.02, 47.39);
    CGContextAddLineToPoint(ctx,120.18, 52.16);
    CGContextAddLineToPoint(ctx,109.91, 65.51);
    CGContextAddLineToPoint(ctx,110.37, 82.34);
    CGContextAddLineToPoint(ctx,94.5, 76.7);
    CGContextAddLineToPoint(ctx,78.63, 82.34);
    CGContextAddLineToPoint(ctx,79.09, 65.51);
    CGContextAddLineToPoint(ctx,68.82, 52.16);
    CGContextAddLineToPoint(ctx,84.98, 47.39);
    CGContextClosePath(ctx);
    
    
    CGContextDrawPath(ctx, kCGPathFillStroke);

}
FirstView.m
#import "FirstView.h"
#import "YJSCLayer.h"

@implementation FirstView

- (instancetype)initWithFrame:(CGRect)frame{
    NSLog(@"initwithFrame");
    if(self = [super initWithFrame:frame]){
        YJSCLayer * layer = [[YJSCLayer alloc]init];
        layer.bounds = CGRectMake(0, 0, 185, 185);
        layer.position = CGPointMake(160, 284);
        layer.backgroundColor = [UIColor colorWithRed:0 green:146/255.0 blue:1.0 alpha:1.0].CGColor;
        //顯示圖層
        [layer setNeedsDisplay];
        
        [self.layer addSublayer:layer];
    }
    return self;
}

- (void)drawRect:(CGRect)rect{
    NSLog(@"2-drawRect:");
    NSLog(@"CGContext:%@",UIGraphicsGetCurrentContext());//得到的當(dāng)前圖形上下文正是drawLayer中傳遞的
    [super drawRect:rect];
}

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
    NSLog(@"1-drawLayer:inContext:");
    NSLog(@"CGContext:%@",ctx);
    [super drawLayer:layer inContext:ctx];
}

@end
#import "ViewController.h"
#import "FirstView.h"

#define PHONE_HEIGHT 150

//角度轉(zhuǎn)弧度
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)

@interface ViewController ()<CALayerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    FirstView * view = [[FirstView alloc]initWithFrame:[UIScreen mainScreen].bounds];
    view.backgroundColor = [UIColor colorWithRed:249.0/255.0 green:249.0/255.0 blue:249.0/255.0 alpha:1];
    
    [self.view addSubview:view];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蕊唐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子烁设,更是在濱河造成了極大的恐慌替梨,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件装黑,死亡現(xiàn)場離奇詭異副瀑,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)恋谭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門糠睡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人疚颊,你說我怎么就攤上這事狈孔。” “怎么了材义?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵均抽,是天一觀的道長。 經(jīng)常有香客問我其掂,道長油挥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任清寇,我火速辦了婚禮喘漏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘华烟。我一直安慰自己翩迈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布盔夜。 她就那樣靜靜地躺著负饲,像睡著了一般堤魁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上返十,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天妥泉,我揣著相機(jī)與錄音,去河邊找鬼洞坑。 笑死盲链,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的迟杂。 我是一名探鬼主播刽沾,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼排拷!你這毒婦竟也來了侧漓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤监氢,失蹤者是張志新(化名)和其女友劉穎布蔗,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浪腐,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纵揍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了牛欢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骡男。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖傍睹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情犹菱,我是刑警寧澤拾稳,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站腊脱,受9級(jí)特大地震影響访得,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜陕凹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一悍抑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧杜耙,春花似錦搜骡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谈竿。三九已至,卻和暖如春摸吠,著一層夾襖步出監(jiān)牢的瞬間空凸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工寸痢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留呀洲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓啼止,卻偏偏與公主長得像两嘴,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子族壳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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