Quartz2D

学习链接

Quartz2D 绘图

画线的三个步骤:

  1. 获取上下文
  2. 绘图
  3. 渲染

参考链接:http://www.cnblogs.com/wendingding/p/3782489.html

Quartz2D 细节

图形上下文栈:

程序启动,显示自定义的view。当程序第一次显示在我们眼前的时候,程序会调用drawRect:方法,在里面获取了图形上下文(在内存中拥有了),然后利用图形上下文保存绘图信息,可以理解为图形上下文中有一块区域用来保存绘图信息,有一块区域用来保存绘图的状态(线宽,圆角,颜色)。直线不是直接绘制到view上的,可以理解为在图形上下文中有一块单独的区域用来先绘制图形,当调用渲染方法的时候,再把绘制好的图形显示到view上去。

在绘制图形区域,会去保存绘图状态区域中查找对应的状态信息(线宽,圆角,颜色),然后在绘图区域把对第一条直线绘制完成。其实在渲染之前,就已经把直线在绘制图形区域画好了。

在获取图形上下文之后,通过 CGContextSaveGState(ctx); 方法,把当前获取的上下文拷贝一份,保存一份最纯洁的图形上下文。
在画第二条线之前,使用CGContextRestoreGState(ctx);方法,还原开始的时候保存的那份最纯洁的图形上下文。

- (void)drawRect:(CGRect)rect
  {
      //获取上下文
      CGContextRef ctx=UIGraphicsGetCurrentContext();
      //保存一份最初的图形上下文
      CGContextSaveGState(ctx);

      //绘图
      //第一条线
     CGContextMoveToPoint(ctx, 20, 100);
     CGContextAddLineToPoint(ctx, 100, 320);

     //设置第一条线的状态
     //设置线条的宽度
     CGContextSetLineWidth(ctx, 12);
     //设置线条的颜色
     [[UIColor brownColor]set];
     //设置线条两端的样式为圆角
     CGContextSetLineCap(ctx,kCGLineCapRound);
     //对线条进行渲染
     CGContextStrokePath(ctx);

     //还原开始的时候保存的那份最纯洁的图形上下文
     CGContextRestoreGState(ctx);
     //第二条线
     CGContextMoveToPoint(ctx, 40, 200);
     CGContextAddLineToPoint(ctx, 80, 100);

     //清空状态
 //    CGContextSetLineWidth(ctx, 1);
 //    [[UIColor blackColor]set];
 //    CGContextSetLineCap(ctx,kCGLineCapButt);

     //渲染
     CGContextStrokePath(ctx);
}

图形上下文栈机制

  • 画第一条线的时候,会把当前的图形上下文拷贝一份保存到** 图形上下文栈 **中。
  • 画第二条线的时候,去图形上下文栈中取出栈顶的绘图信息,作为第二条线的状态信息,第二条线的状态信息也是据此(最初保存的那份图形上下文)进行绘制。
  • 注意: 在栈里保存了几次,那么就可以取几次(比如不能保存了1次,取两次,在取第二次的时候,栈里为空会直接挂掉)。

绘图相关

  • drawRect:方法不能由我们自己手动调用,只能由系统来调用。
  • drawRect:调用的时机:当第一次显示或者一个重绘事件发生时调用。
  • setNeedsDisplay方法:重新绘制,调用这个方法就会通知自定义的view重新绘制画面,调用drawRect:。
  • 提示:当一个view从xib或storyboard创建出来时,会调用awakefromnib方法。

Tips:

下面两个方法的调用顺序
-(void)awakeFromNib
-(id)initWithCoder:(NSCoder *)aDecoder

提示:

  • 如果view是从xib或storyboard中创建可以调用awakefromnib方法。
  • 归档。从文件创建view,其实会先调用initwithcoder这个方法。xib和storyboard也是文件。

上面两个方法,-(id)initWithCoder:(NSCoder *)aDecoder会先调用。实现该方法需要实现NSCoding协议,由于创建的UIView默认就已经实现了该协议。

两个定时器
  • 第一个:
    [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateImage) userInfo:nil repeats:YES];
    ** 说明:** NSTimer一般用于定时的更新一些非界面上的数据,告诉多久调用一次

  • 第二个:

        CADisplayLink *display= [CADisplayLink displayLinkWithTarget:self selector:@selector(updateImage)];
        [display addToRunLoop:[NSRunLoopmainRunLoop] forMode:NSDefaultRunLoopMode];

** 说明:** CADisplayLink刷帧,默认每秒刷新60次。该定时器创建之后,默认是不会执行的,需要把它加载到消息循环中

Quartz2D使用(绘图路径)

绘图路径
  1. 创建路径 cgmutablepathref 调用该方法相当于创建了一个路径,这个路径用来保存绘图信息。
  2. 把绘图信息添加到路径里边。以前的方法是点的位置添加到ctx(图形上下文信息)中,ctx 默认会在内部创建一个path用来保存绘图信息。在图形上下文中有一块存储空间专门用来存储绘图信息,其实这块空间就是CGMutablePathRef。
  3. 把路径添加到上下文中。

context绘图

    //1.获取图形上下文
    CGContextRef ctx=UIGraphicsGetCurrentContext();
    //2.绘图(画线)
    //设置起点
    CGContextMoveToPoint(ctx, 20, 20);
    //设置终点
    CGContextAddLineToPoint(ctx, 200, 300);
    //渲染
    CGContextStrokePath(ctx);

路径方法

//1.获取图形上下文
    CGContextRef ctx=UIGraphicsGetCurrentContext();

    //2.绘图
    //2.1创建一条直线绘图的路径
    //注意:但凡通过Quartz2D中带有creat/copy/retain方法创建出来的值都必须要释放
    CGMutablePathRef path=CGPathCreateMutable();
    //2.2把绘图信息添加到路径里
    CGPathMoveToPoint(path, NULL, 20, 20);
    CGPathAddLineToPoint(path, NULL, 200, 300);
    //2.3把路径添加到上下文中
    //把绘制直线的绘图信息保存到图形上下文中
    CGContextAddPath(ctx, path);

    //3.渲染
    CGContextStrokePath(ctx);

    //4.释放前面创建的两条路径
    //第一种方法
    CGPathRelease(path);
    //第二种方法
    //    CFRelease(path);
}

** 说明 ** 上面两个代码是等价的。
使用路径绘图可读性比较好,便于区分。使用path,则一个path就代表一条路径。绘制多个图形的情况下,建议使用Path来绘制。

- (void)drawRect:(CGRect)rect
{
    //1.获取图形上下文
    CGContextRef ctx=UIGraphicsGetCurrentContext();

    //2.绘图
    //2.a 画一条直线
    //2.a.1创建一条绘图的路径
    //注意:但凡通过Quartz2D中带有creat/copy/retain方法创建出来的值都必须要释放
    CGMutablePathRef path=CGPathCreateMutable();

    //2.a.2把绘图信息添加到路径里
    CGPathMoveToPoint(path, NULL, 20, 20);
    CGPathAddLineToPoint(path, NULL, 200, 300);

    //2.a.3把路径添加到上下文中
    //把绘制直线的绘图信息保存到图形上下文中
    CGContextAddPath(ctx, path);


    //2.b画一个圆
    //2.b.1创建一条画圆的绘图路径(注意这里是可变的,不是CGPathRef)
    CGMutablePathRef path1=CGPathCreateMutable();

    //2.b.2把圆的绘图信息添加到路径里
    CGPathAddEllipseInRect(path1, NULL, CGRectMake(50, 50, 100, 100));

    //2.b.3把圆的路径添加到图形上下文中
    CGContextAddPath(ctx, path1);


    //3.渲染
    CGContextStrokePath(ctx);

    //4.释放前面创建的两条路径
    //第一种方法
    CGPathRelease(path);
    CGPathRelease(path1);
    //第二种方法
//    CFRelease(path);
}

提示:如果是画线,那么就创建一条路径(path)用来保存画线的绘图信息,如果又要重新画一个圆,那么就可以创建一条新的路径来专门保存画圆的绘图信息。
注意:
但凡通过quarzt2d中带有creat/copy/retain方法创建出来的值都必须手动的释放
有两种方法可以释放前面创建的路径:

 CGPathRelease(path);
 CFRelease(path);

说明:CFRelease属于更底层的cocafoundation框架

补充知识点

画四边形的一些方法:

  1. 通过连接固定的点绘制四边形
  2. 指定起点和宽高绘制四边形
  3. 把第二种方式中的两步合并成一步。
  4. 绘制实心的四边形,注意没有空心的方法
  5. 画根线,设置线条的宽度(通过这种方式可以画斜的四边形)
- (void)drawRect:(CGRect)rect
{
    //获取图形上下文
    CGContextRef ctx=UIGraphicsGetCurrentContext();
    //第一种画法,通过连接固定的点绘制四边形
//    CGContextMoveToPoint(ctx, 0, 20);
//    CGContextAddLineToPoint(<#CGContextRef c#>, <#CGFloat x#>, <#CGFloat y#>);
//    CGContextAddLineToPoint(<#CGContextRef c#>, <#CGFloat x#>, <#CGFloat y#>);
//    CGContextAddLineToPoint(<#CGContextRef c#>, <#CGFloat x#>, <#CGFloat y#>);

    //第二种方式:指定起点和宽高绘制四边形
//    CGContextAddRect(ctx, CGRectMake(20, 20, 200, 100));
//    //渲染
//    CGContextStrokePath(ctx);

    //第三种方式:二种的两步合并成一步。
    //画空心的四边形
//    CGContextStrokeRect(ctx, CGRectMake(20, 20, 200, 100));
//    //画实心的四边形
//    CGContextFillRect(ctx, CGRectMake(20, 20, 200, 100));

    //第四种方式(oc的方法):绘制实心的四边形,注意没有空心的方法
    UIRectFill(CGRectMake(20, 20, 200, 100));

    //第五种方式:画根线,设置线条的宽度(通过这种方式可以画斜的四边形)
//    CGContextMoveToPoint(ctx, 20, 20);
//    CGContextAddLineToPoint(ctx, 100, 200);
//    CGContextSetLineWidth(ctx, 50);
//    //注意,线条只能画成是空心的
//    CGContextStrokePath(ctx);

}

Quartz2D使用(截屏)

完成截屏功能的核心代码:- (void)renderInContext:(CGContextRef)ctx;调用某个view的layer的renderInContext:方法即可

相关的步骤:

  1. 创建一个bitmap的上下文
  2. 将屏幕绘制带上下文中
  3. 从上下文中取出绘制好的图片
  4. 保存图片到相册
- (void)viewDidLoad
{
    [super viewDidLoad];
}

- (IBAction)BtnClick:(UIButton *)sender {

    //延迟两秒保存
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //获取图形上下文
        //    UIGraphicsBeginImageContext(self.view.frame.size);
        UIGraphicsBeginImageContext(self.contentView.frame.size);
        //将view绘制到图形上下文中

        //    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
        [self.contentView.layer renderInContext:UIGraphicsGetCurrentContext()];


        //将截屏保存到相册
        UIImage *newImage=UIGraphicsGetImageFromCurrentImageContext();

        UIImageWriteToSavedPhotosAlbum(newImage,self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
    });
}

 - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
    if (error) {
        [MBProgressHUD showError:@"保存失败,请检查是否拥有相关的权限"];
    }else
    {
//        [MBProgressHUD showMessage:@"保存成功!"];
        [MBProgressHUD showSuccess:@"保存成功!"];
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容

  • Quartz2D以及drawRect的重绘机制字数1487 阅读21 评论1 喜欢1一、什么是Quartz2D Q...
    PurpleWind阅读 757评论 0 3
  • Quartz2D 简介 Quartz2D是二维(平面)的绘图引擎(经包装的函数库,方便开发者使用。也就是说苹果帮我...
    iOS_Cqlee阅读 624评论 0 2
  • 什么是Quartz2D 是一个二维的绘图引擎,同时支持iOS和Mac系统 Quartz2D的API是纯C语言的,它...
    Mario_ZJ阅读 571评论 0 1
  • 什么是Quartz2D? Quartz 2D是一个二维图形绘制引擎,支持iOS环境和Mac OS X环境。我们可以...
    小番茄阳阳阅读 931评论 0 4
  • 什么是Quartz 2D 1>Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac OS X系统(跨平台,...
    青葱烈马阅读 734评论 0 3