IOS开发—Quartz 2D介绍

Quartz 2D学习记录

Quartz 2D简单介绍

一、什么是Quartz 2D

Quarz 2D是一个二维绘画引擎,同时支持ios和mac,其API是Core Graphics框架的,是纯C语言的。IOS系统提供的大部分控件的内容都是通过Quartz 2D画出来的,因此Quartz 2D的一个很重要的价值是:自定义view(自定义UI控件)。

二、一个重要的概念:图形上下文

图形上下文(Graphics context)是一个CGContextRef数据,其作用是:

  1. 保存绘图信息、绘图属性
  2. 绘制目标图案
  3. 输出绘制好的图案到输出目标去,即渲染到什么地方去(可以是PDF文件、bitmap或者显示器的窗口上)

三、自定义view,即绘制view

在view中实现- (void)drawRect:(CGRect)rect方法,然后在方法中:

1. 取得跟当前view相关联的图形上下文;

2. 绘制相应的图形内容

3. 利用图形上下文将绘制好的图形内容渲染显示到view上面

Quartz 2D简单使用

代码示例

    //绘制步骤:1、获取当前视图的图形上下文 2、开始绘图 3、渲染绘制内容

    /**绘制直线**/

    //1、获取当前视图的图形上下文(图形上下文决定绘制的输出目标)
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    //2、开始绘图
    //设置起点
    CGContextMoveToPoint(ctx, 20, 50);
    //设置终点
    CGContextAddLineToPoint(ctx, 300, 50);
    //设置线条属性
    //设置颜色
    CGContextSetStrokeColorWithColor(ctx, [UIColor purpleColor].CGColor);
    //另外一种设置颜色的方式
//    [[UIColor purpleColor] set];
    //设置线条宽度
    CGContextSetLineWidth(ctx, 10);
    //设置线条起点和终点的样式为圆角
    CGContextSetLineCap(ctx, kCGLineCapRound);

    //3、将画布上绘制的内容渲染到view的layer上
    CGContextStrokePath(ctx);

    /**绘制三角形**/

    //设置起点
    CGContextMoveToPoint(ctx, 150, 80);
    //设置第一个拐点
    CGContextAddLineToPoint(ctx, 220, 150);
    //设置第二个拐点
    CGContextAddLineToPoint(ctx, 80, 150);
    //设置第三个点(终点)
//    CGContextAddLineToPoint(ctx, 150, 80);
    //可以用下面方法代替 缝合起点和终点
    CGContextClosePath(ctx);
    //设置线条的拐点转角样式为圆角
    CGContextSetLineJoin(ctx, kCGLineJoinRound);
    //渲染
    CGContextStrokePath(ctx);

    /**绘制空心四边形**/
    CGContextAddRect(ctx, CGRectMake(40, 200, 200, 100));
    //设置空心(线条)颜色
//    CGContextSetStrokeColorWithColor(ctx, [UIColor lightGrayColor].CGColor);
    //也可以这样设置颜色
    [[UIColor lightGrayColor] setStroke];
    //设置线条宽度
    CGContextSetLineWidth(ctx, 10);
    //渲染(空心的)
    CGContextStrokePath(ctx);

    /**绘制实心四边形**/
    CGContextAddRect(ctx, CGRectMake(40, 320, 200, 100));
    //设置实心颜色
//    CGContextSetFillColorWithColor(ctx, [UIColor orangeColor].CGColor);
    [[UIColor orangeColor] setFill];
    //渲染(实心的)
    CGContextFillPath(ctx);

    /**绘制圆(可以用绘制椭圆的方式画圆)**/
    //参数依次为圆心x,圆心y,半径,开始位置的弧度,结束位置的弧度,绘制路径(1为顺时针,0为逆时针)
    //由于Quartz2D的坐标系是x轴向右,y轴向上,不同于UIKit坐标系。因此在不将Quartz2D坐标系翻转的情况下,画出来的图形是与原图形关于x轴对称的。
    CGContextAddArc(ctx, 100, 520, 50, 0, M_PI_2, 1);
    CGContextStrokePath(ctx); //空心
//    CGContextFillPath(ctx); //实心

    /**绘制椭圆**/
    CGContextAddEllipseInRect(ctx, CGRectMake(230, 400, 120, 200));
    CGContextSetStrokeColorWithColor(ctx, [UIColor blueColor].CGColor);
    CGContextStrokePath(ctx);

    /**绘制弧线**/
//    CGContextAddArcToPoint(ctx, 100, 200, 100, 200, 50);
    CGContextAddArc(ctx, 200, 200, 100, 0, M_PI, 1);
    CGContextSetStrokeColorWithColor(ctx, [UIColor cyanColor].CGColor);
    CGContextStrokePath(ct

绘制结果

图形上下文栈

一、绘制原理

举个例子,假如要绘制两条线,一条红色一条默认的黑色。先绘制红色线,绘制完毕渲染上去后,再去绘制第二条。绘制第二条的时候如果不重新设置绘画颜色,那么绘制出来的线条也是红色的。也就是说,绘制属性如果不对其清空(即重新设置)是默认保留在图形上下文上的。因此可以这样理解:

一个图形上下文有3块区域,分别是绘制属性,图像信息,绘制区域:

  1. 绘制属性:包括画笔的颜色、线条宽度、是否圆角等等;
  2. 绘图信息:比如要绘制一条直线,那么保存了线条的起点和终点,绘制圆,保存了半径、中点坐标、起点终点、方向等等。也就是说,绘图信息中保存的是绘图路径,这个在下面会详细介绍。
  3. 绘图区域:这个区域不是指视图上的区域,而是图形上下文上的绘制区域,因为绘画是在图形上下文上绘制好之后才被渲染到视图的制定区域上的。

二、保存图形上下文绘制属性

前面说过如果要绘制多个不同属性的图形,那么每次渲染好一个图形后就要重新设置绘制属性,通常绘制多个图形都是这样做的。有时候可能用到一个简单的方法:即在绘制一个图形前先保存当前图形上下文中的绘制属性,这个绘制属性会被保存到图形上下文栈上,如果下次需要绘制同样属性的图形,直接把这个绘制属性从栈顶取出来(恢复)就好了。需要注意的是保存一次只能取一次,可以保存多次,但是每次只从栈顶取

代码示例

/**保存绘制属性(以绘制3条线为例,第一条第三条属性一致)**/
//第一条
CGContextMoveToPoint(ctx, 20, 300);
CGContextAddLineToPoint(ctx, 200,300);
//设置绘制属性
CGContextSetLineWidth(ctx, 10);
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetStrokeColorWithColor(ctx, [UIColor orangeColor].CGColor);
CGContextStrokePath(ctx);

//第二条线
//先保存当前的绘制属性
CGContextSaveGState(ctx);
CGContextMoveToPoint(ctx, 20, 400);
CGContextAddLineToPoint(ctx, 200, 400);
//设置新的绘制属性
CGContextSetLineWidth(ctx, 5);
CGContextSetLineCap(ctx, kCGLineCapButt);
CGContextSetStrokeColorWithColor(ctx, [UIColor blueColor].CGColor);
CGContextStrokePath(ctx);

//第三条线
//取出(恢复)之前保存的绘制属性
CGContextRestoreGState(ctx);
CGContextMoveToPoint(ctx, 20, 500);
CGContextAddLineToPoint(ctx, 200, 500);
CGContextStrokePath(ctx);

绘制结果

矩阵操作

一、矩阵操作介绍

矩阵操作主要有旋转操作、缩放操作、平移操作,是以视图左上角为原点进行的。对矩阵的操作一定要在绘制之前完成,不然绘制完了再操作无效。

二、代码说明

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    //矩阵旋转45度(参数为图形上下文、旋转角度)是以左上角为旋转点的
    //设置矩阵操作要在绘制前完成
//    CGContextRotateCTM(ctx, M_PI_4);

    //缩放(参数为图形上下文,x方向缩放比例,y方向缩放比例)
//    CGContextScaleCTM(ctx, 0.5, 0.5);

    //平移(参数为图形上下文,x方向平移距离,y方向平移距离)
    CGContextTranslateCTM(ctx, 100, 100);

    CGContextAddRect(ctx, CGRectMake(100, 100, 100, 100));

    //标记
    NSString *loc1 = @"1";
    NSString *loc2 = @"2";
    [loc1 drawAtPoint:CGPointMake(99, 99) withAttributes:nil];
    [loc2 drawAtPoint:CGPointMake(201, 99) withAttributes:nil];

    CGContextStrokePath(ctx);

剪切操作

一、剪切介绍

指剪切掉指定区域意外的部分,只保留该区域内的内容。

原则:先设置好剪切区域,或者说剪切方法,再去绘制相关内容。

二、代码相关

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //剪切自定义区域意外的部分(以剪切方法为三角形,剪切内容为图片为例)
//    //    CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 50, 50));
//    CGContextMoveToPoint(ctx, 100, 100);
//    CGContextAddLineToPoint(ctx, 60, 150);
//    CGContextAddLineToPoint(ctx, 140, 150);
//    CGContextClosePath(ctx);

//    CGContextClip(ctx);

    //剪切指定矩形区域意外的部分
    CGContextClipToRect(ctx, CGRectMake(80, 100, 10, 10));
    UIImage *image = [UIImage imageNamed:@"google"];
    [image drawAtPoint:CGPointMake(80, 100)];

绘图路径

一、绘图路径介绍

我们之前画一条直线,都是直接设置好它的起点和终点,然后就开始画了。画一个圆,设置好圆心半径起点终点和方向即可。事实上,我们设置好这些绘图信息后,系统会默认创建一条绘图路径,画图就是根据这条路径来画的。一条线对应一条路径,一个圆对应另一条路径。那么我们自然可以通过手动创建路径的方式绘制,需要绘制几个图案,就要创建几条路径。

二、注意点

A、Quartz2D中所有通过creat/copy/retain方法创建出来的值都要释放,以path为例:

  1. CGPathRelease(path);或
  2. CFRelease(path);

B、可以将要绘制的所有路径加入到图形上下文后,最后一次性渲染。

三、代码示例

    //绘制一条直线的两种方法(两种方式是等效的)
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextMoveToPoint(ctx, 20, 200);
    CGContextAddLineToPoint(ctx, 300, 200);
    CGContextStrokePath(ctx);

    //手动创建路径绘制
    //创建一条路径
    CGMutablePathRef path = CGPathCreateMutable();
    //添加绘图信息到路径
    CGPathMoveToPoint(path, NULL, 20, 300);
    CGPathAddLineToPoint(path, NULL, 300, 300);
    //将路径添加到图形上下文
    CGContextAddPath(ctx, path);

    //创建另一条路径
    CGMutablePathRef path2 = CGPathCreateMutable();
    CGPathAddEllipseInRect(path2, NULL, CGRectMake(100, 400, 100, 100));
    CGContextAddPath(ctx, path2);
    CGContextStrokePath(ctx);

    //渲染所有路径对应的图案
    CGContextStrokePath(ctx);

    //Quartz2D中所有通过creat/copy/retain方法创建出来的值都要释放
    CGPathRelease(path);
    CGPathRelease(path2);
    //或者
//    CFRelease(path);

运行结果

Bitmap

一、bitmap图形上下文

Quartz2D提供了以下几种类型的图形上下文

  • Bitmap Graphics Context
  • PDF Graphics Context
  • Window Graphics Context
  • Layer Graphics Context
  • Printer Graphics Context

常用的是Bitmap Graphics Context。所谓Bitmap,其实就是UIImage,这也是最常用到的图形上下文,通常用它来生成一张图片。步骤如下:

  1. 创建一个bitmap图形上下文(有两种方式)

    A.UIGraphicsBeginImageContext(<#CGSize size#>);

    B.UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale);

    这两种方法都可以创建一个bitmap图形上下文,但是第一种创建的图片清晰度和质量没有第二种好。方法二接收的参数依次为:

    • size:指定创建出来的bitmap尺寸大小
    • opaque:是否透明,YES表示不透明,NO透明
    • scale:缩放比例,0为不缩放
  2. 获取创建好的bitmap图形上下文然后在上面做文章(画图)
  3. 取出绘制好的图片
  4. 关闭bitmap图形上下文
  5. 释放需要释放的变量

代码示例(截屏)

//点击按钮截屏
- (void)actionShot:(UIButton *)sender{

    //可以隐藏按钮,渲染完后显示回来
    self.buttonShot.hidden = YES;

    //创建图形上下文
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.view.frame.size.width, self.view.frame.size.height), NO, 0);
    //获取图形上下文并将当前屏幕渲染到图形上下文上
    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    [delegate.window .layer renderInContext:UIGraphicsGetCurrentContext()];
    //从图形上下文中取出绘制好的图片
    UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
    //关闭图形上下文
    UIGraphicsEndImageContext();

    self.buttonShot.hidden = NO;

//    //截屏完毕 有时候可能想获取屏幕中指定区域的图片,如下操作
//    //得到截屏的cgimage
    CGImageRef image = screenImage.CGImage;

    //设置目标区域,注意这里需要考虑retina分辨率的放大倍数,以iphone6plus为例,在原尺寸的基础上*3,这里就不判断了。
    CGRect rect = CGRectMake(0, 0, screenImage.size.width*3, screenImage.size.height*3);
    //取出目标区域的图片
    CGImageRef targetImage = CGImageCreateWithImageInRect(image, rect);
    //最终图片
    UIImage *finalImage = [UIImage imageWithCGImage:targetImage];

    //保存到相册
    UIImageWriteToSavedPhotosAlbum(finalImage, self, @selector(image: didFinishSavingWithError:contextInfo:), nil);

    //保存到沙盒
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *currentTime = [dateFormatter stringFromDate:[NSDate date]];
    NSString *imagePath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"ScreenShot_%@.png",currentTime]];
    NSData *imageDate = UIImagePNGRepresentation(finalImage);
    [imageDate writeToFile:imagePath atomically:YES];

    CGImageRelease(targetImage);
}
//保存至相册后的回调
- (void)image: (UIImage *) image didFinishSavingWithError: (NSError *) error contextInfo: (void *) contextInfo
{
    NSString *msg = nil ;
    if(error != NULL){
        msg = @"保存图片失败" ;
    }else{
        msg = @"保存图片成功" ;
    }
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"保存图片结果提示"
                                                    message:msg
                                                   delegate:self
                                          cancelButtonTitle:@"确定"
                                          otherButtonTitles:nil];
    [alert show];
}

Quartz2D内存管理

前面讲绘图路径的时候提到过内存管理,下面再总结一下:

  • 凡是使用含有“create”或“copy”的函数创建的对象,使用完毕后必需释放,否则将导致内存泄露。不含“create”或“copy”的则不需要释放。
  • 如果retain了一个对象,不再使用时需要release。已CGColorSpace为例,如果创建了一个CGColorSpace对象,则使用函数CGColorSpaceRetain和CGColorSpaceRelease来retain和release对象。也可以使用Core Foundation的CFRetain和CFRelease。注意不能传递NULL值给这些函数。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-28 06:42:49

IOS开发—Quartz 2D介绍的相关文章

iOS 开发 Quartz 2D+ UIBezierPath绘图大全详解

Quartz 2D 使用大全结构图 UIKIt UIBezierPath Core Graphics OpenGL ES Quartz2D的区别和联系 UIKIt:UIKit中的控件都是基于Core Graphics实现的 UIBezierPath:UIBezierPath属于UIKit,它是苹果对复杂的Core Graphics进行的封装,方便我们用OC语言进行简单的绘图 Core Graphics:是一套基于C语言的API,支持向量图形,线.形状.图案.路径.剃度.位图图像和pdf 内容的绘

iOS开发——图形编程OC篇&amp;(一)Quartz 2D介绍

Quartz 2D介绍 一.什么是Quartz2D Quartz 2D是?个二维绘图引擎,同时支持iOS和Mac系统 Quartz 2D能完成的工作: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成PDF 截图\裁剪图片 自定义UI控件 二.Quartz2D在iOS开发中的价值 为了便于搭建美观的UI界面,iOS提供了UIKit框架,??有各种各样的UI控件 UILabel:显?文字 UIImageView:显示图片 UIButton:同时显示图片和?字

[翻译] iOS开发工具的介绍(第一部分)

IOS DEVELOPMENT TIPS & TRICKS - PART I http://blog.trifork.com/2013/12/19/ios-development-tips-tricks-part-i/ As you might know, I am very fond of developing apps for the iOS platform. I started back in mid-2009 by trying to create an app for the Dut

iOS开发UI—UIWindow介绍

一.简单介绍 UIWindow是一种特殊的UIView,通常在一个app中只会有一个UIWindow iOS程序启动完毕后,创建的第一个视图控件就是UIWindow,接着创建控制器的view,最后将控制器的view添加到UIWindow上,于是控制器的view就显示在屏幕上了 一个iOS程序之所以能显示到屏幕上,完全是因为它有UIWindow.也就说,没有UIWindow,就看不见任何UI界面 补充:UIWindow是创建的第一个视图控件(创建的第一个对象是UIapplication)如下图:

iOS开发&gt;学无止境 - POP 介绍与使用实践(快速上手动画)

作者:里脊串(@里脊串) 网址:http://adad184.com/2015/03/11/intro-to-pop/   前言 动画在APP开发过程中 大家多多少少都会接触到 而且随着ios7的扁平化风格启用之后 越来越多的APP开始尝试加入各种绚丽的动画交互效果以增加APP的用户体验(当然 还是以国外的APP居多) 有过相关开发经验的同学肯定知道在iOS中 动画相关的部分都是基于Core Animation 但是今天我们不讨论Core Animation 今天的主角是POP -来自于Face

iOS开发多线程理论介绍

前言 线程是用来执行任务的,线程彻底执行完任务A才能去执行任务B.为了同时执行两个任务,产生了多线程. 就我们日常生活的例子来说: (1)我打开一个视频软件,我开辟一个线程A让它执行下载任务,我开辟一个线程B,用来播放视频.我开辟两个线程后,这两个任务能同时执行,如果我开辟一个线程,只有下载任务完成,才能去执行播放任务. (2)线程相当于店里的服务员,一个服务员同时只能做一件事情,多顾几个服务员,就能同时做很多事情. 在了解多线程之前我们先来介绍一下进程和线程 进程 进程是操作系统中运行的程序专

iOS开发:bitcode介绍和使用cocoapods出现“target overrides the `OTHER_LDFLAGS`……”的解决方案

在开发中,不免需要引入第三方库,但是因为库的问题,会发生很多错误.如: 1.因为一些第三方库不包含bitcode就会报错: 一次使用xcode7.1时,发现编译失败,报错信息: umeng message.sdk does not contain bitcode. You must rebuild it with bitcode enabled (Xcodesetting ENABLE_BITCODE), obtain an updated library from the vendor, or

iOS开发-UIActionSheet简单介绍

UIActionSheet和UIAlertView都是ios系统自带的模态视图,模态视图的一个重要的特性就是在显示模态视图的时候可以阻断其他视图的事件响应.一般情况下我们对UIAlertView使用的比较多,UIActionSheet相对来说情况少一点,偶尔作为一个上拉菜单来展示还是非常有用的.通常如果显示一个模态的视图,可以自定义一个UIViewController,不过里面的内容和动画实现起来工作量还是非常多的. UIActionSheet介绍 介绍UIActionSheet之前需要简单的看

iOS开发ApplePay的介绍与实现

1.Apple Pay的介绍 Apple Pay官方 1.1 Apple Pay概念 Apple Pay,简单来说, 就是一种移动支付方式.通过Touch ID/ Passcode,用户可使用存储在iPhone 6, 6p等之后的新设备上的信用卡和借记卡支付证书来授权支付: 它是苹果公司在2014苹果秋季新品发布会上发布的一种基于NFC的手机支付功能,于2014年10月20日在美国正式上线,2016年2月18日凌晨5:00, Apple Pay 业务在中国上线. 1.2 使用前提 设备支持 iP