转自:http://www.cnblogs.com/wendingding/p/3782489.html

一、qurza2d是怎么将绘图信息和绘图的属性绘制到图形上下文中去的?

说明:

新建一个项目,自定义一个view类和storyboard关联后,重写该类中的drowrect方法。
画线的三个步骤:
(1)获取上下文
(2)绘图
(3)渲染
要求:画两条单独的线
代码和效果图:
 1 - (void)drawRect:(CGRect)rect
2 {
3 //获取上下文
4 CGContextRef ctx=UIGraphicsGetCurrentContext();
5 //绘图
6 //第一条线
7 CGContextMoveToPoint(ctx, 20, 100);
8 CGContextAddLineToPoint(ctx, 100, 320);
9
10 //第二条线
11 CGContextMoveToPoint(ctx, 40, 200);
12 CGContextAddLineToPoint(ctx, 80, 100);
13 //渲染
14 CGContextStrokePath(ctx);
15
16 }
效果图:
设置线段的宽度:两头为圆形,颜色等。
代码和效果图(发现第二条线也被渲染成第一条线的样式和状态)
 1 - (void)drawRect:(CGRect)rect
2 {
3 //获取上下文
4 CGContextRef ctx=UIGraphicsGetCurrentContext();
5 //绘图
6 //第一条线
7 CGContextMoveToPoint(ctx, 20, 100);
8 CGContextAddLineToPoint(ctx, 100, 320);
9
10 //设置第一条线的状态
11 //设置线条的宽度
12 CGContextSetLineWidth(ctx, 12);
13 //设置线条的颜色
14 [[UIColor brownColor]set];
15 //设置线条两端的样式为圆角
16 CGContextSetLineCap(ctx,kCGLineCapRound);
17 //对线条进行渲染
18 CGContextStrokePath(ctx);
19
20 //第二条线
21 CGContextMoveToPoint(ctx, 40, 200);
22 CGContextAddLineToPoint(ctx, 80, 100);
23 //渲染
24 CGContextStrokePath(ctx);
25
26 }

效果图:

新的需求:要让两条线的颜色不一样,要求第二条线变成原版的样子。要达到上面的要求,有以下几种做法:

第一种做法:
在对第二条线进行设置的时候,清空它的状态
 1 - (void)drawRect:(CGRect)rect
2 {
3 //获取上下文
4 CGContextRef ctx=UIGraphicsGetCurrentContext();
5 //绘图
6 //第一条线
7 CGContextMoveToPoint(ctx, 20, 100);
8 CGContextAddLineToPoint(ctx, 100, 320);
9
10 //设置第一条线的状态
11 //设置线条的宽度
12 CGContextSetLineWidth(ctx, 12);
13 //设置线条的颜色
14 [[UIColor brownColor]set];
15 //设置线条两端的样式为圆角
16 CGContextSetLineCap(ctx,kCGLineCapRound);
17 //对线条进行渲染
18 CGContextStrokePath(ctx);
19
20 //第二条线
21 CGContextMoveToPoint(ctx, 40, 200);
22 CGContextAddLineToPoint(ctx, 80, 100);
23
24 //清空状态
25 CGContextSetLineWidth(ctx, 1);
26 [[UIColor blackColor]set];
27 CGContextSetLineCap(ctx,kCGLineCapButt);
28
29 //渲染
30 CGContextStrokePath(ctx);
31
32 }
 
第二种做法:
把第一条线从开始绘制到渲染的代码剪切到第二条线渲染完成之后,这样先绘制并渲染了第一条线,该线并没有对绘制信息进行过设置,显示出来的第二条线即位系统默认的效果。
 1 - (void)drawRect:(CGRect)rect
2 {
3 //获取上下文
4 CGContextRef ctx=UIGraphicsGetCurrentContext();
5 //绘图
6
7 //第二条线
8 CGContextMoveToPoint(ctx, 40, 200);
9 CGContextAddLineToPoint(ctx, 80, 100);
10
11 //清空状态
12 // CGContextSetLineWidth(ctx, 1);
13 // [[UIColor blackColor]set];
14
15 // CGContextSetLineCap(ctx,kCGLineCapButt);
16
17 //渲染
18 CGContextStrokePath(ctx);
19
20 //第一条线
21 CGContextMoveToPoint(ctx, 20, 100);
22 CGContextAddLineToPoint(ctx, 100, 320);
23
24 //设置第一条线的状态
25 //设置线条的宽度
26 CGContextSetLineWidth(ctx, 12);
27 //设置线条的颜色
28 [[UIColor brownColor]set];
29 //设置线条两端的样式为圆角
30 CGContextSetLineCap(ctx,kCGLineCapRound);
31 //对线条进行渲染
32 CGContextStrokePath(ctx);
33 }

两种方式完成的效果相同:

 
但是有的情况下,必须要先画第一条线再画第二条线,要求在交叉部分,第二条线盖在第一条线的上面。如果要求是这样,那么只能使用第一种做法,但 是如果现在有新的需求,要求在这个基础上再画两条线,那就需要清空ctx中的状态很多次,很麻烦。为了解决这个问题,下面给大家介绍图形上下文栈。
 
二、绘图的完整过程
程序启动,显示自定义的view。当程序第一次显示在我们眼前的时候,程序会调用drawRect:方法,在里面获取了图形上下文(在内存中拥有了),然后利用图形上下文保存绘图信息,可以理解为图形上下文中有一块区域用来保存绘图信息,有一块区域用来保存绘图的状态(线宽,圆角,颜色)。直线不是直接绘制到view上的,可以理解为在图形上下文中有一块单独的区域用来先绘制图形,当调用渲染方法的时候,再把绘制好的图形显示到view上去。
 
在绘制图形区域,会去保存绘图状态区域中查找对应的状态信息(线宽,圆角,颜色),然后在绘图区域把对第一条直线绘制完成。其实在渲染之前,就已经把直线在绘制图形区域画好了。
如图:
     
说明:这些示意图和本文中的程序代码块,不具备一一对应关系,只是为了说明绘图的完整过程。
调用渲染方法的时候,把绘制图形区域已经画好的图形直接显示到view上,就是我们看到的样子了。
如图:
   
画第二条的时候,如果没有对绘图状态进行重新设置,那么可以发现画第一天线的时候使用的绘图状态还保存在图形上下文中,在第二条线进行渲染之前,会根据第一条线(上一份绘图状态)对第二条线进行相应的设置,渲染后把第二条线显示到屏幕上。
参考代码:
 1 - (void)drawRect:(CGRect)rect
2 {
3 //获取上下文
4 CGContextRef ctx=UIGraphicsGetCurrentContext();
5 //绘图
6 //第一条线
7 CGContextMoveToPoint(ctx, 20, 100);
8 CGContextAddLineToPoint(ctx, 100, 320);
9
10 //设置第一条线的状态
11 //设置线条的宽度
12 CGContextSetLineWidth(ctx, 12);
13 //设置线条的颜色
14 [[UIColor brownColor]set];
15 //设置线条两端的样式为圆角
16 CGContextSetLineCap(ctx,kCGLineCapRound);
17 //对线条进行渲染
18 CGContextStrokePath(ctx);
19
20 //第二条线
21 CGContextMoveToPoint(ctx, 40, 200);
22 CGContextAddLineToPoint(ctx, 80, 100);
23 //渲染
24 CGContextStrokePath(ctx);
25 }
如果清空了状态,则在渲染之前,在绘制图形区域对第二条线进行绘制的时候,会去查找当前的绘图信息(已经更改——清空),根据绘图信息对第二条线进行绘制,调用渲染方法的时候把第二条线显示到view上。
参考代码:
 1 - (void)drawRect:(CGRect)rect
2 {
3 //获取上下文
4 CGContextRef ctx=UIGraphicsGetCurrentContext();
5 //绘图
6 //第一条线
7 CGContextMoveToPoint(ctx, 20, 100);
8 CGContextAddLineToPoint(ctx, 100, 320);
9
10 //设置第一条线的状态
11 //设置线条的宽度
12 CGContextSetLineWidth(ctx, 12);
13 //设置线条的颜色
14 [[UIColor brownColor]set];
15 //设置线条两端的样式为圆角
16 CGContextSetLineCap(ctx,kCGLineCapRound);
17 //对线条进行渲染
18 CGContextStrokePath(ctx);
19
20 //第二条线
21 CGContextMoveToPoint(ctx, 40, 200);
22 CGContextAddLineToPoint(ctx, 80, 100);
23
24 //清空状态
25 CGContextSetLineWidth(ctx, 1);
26 [[UIColor blackColor]set];
27 CGContextSetLineCap(ctx,kCGLineCapButt);
28
29 //渲染
30 CGContextStrokePath(ctx);
31 }
三、图形上下文栈
1.简单说明
在获取图形上下文之后,通过

CGContextSaveGState(ctx);

方法,把当前获取的上下文拷贝一份,保存一份最纯洁的图形上下文。

在画第二条线之前,使用CGContextRestoreGState(ctx);方法,还原开始的时候保存的那份最纯洁的图形上下文。
代码:
 1 - (void)drawRect:(CGRect)rect
2 {
3 //获取上下文
4 CGContextRef ctx=UIGraphicsGetCurrentContext();
5 //保存一份最初的图形上下文
6 CGContextSaveGState(ctx);
7
8 //绘图
9 //第一条线
10 CGContextMoveToPoint(ctx, 20, 100);
11 CGContextAddLineToPoint(ctx, 100, 320);
12
13 //设置第一条线的状态
14 //设置线条的宽度
15 CGContextSetLineWidth(ctx, 12);
16 //设置线条的颜色
17 [[UIColor brownColor]set];
18 //设置线条两端的样式为圆角
19 CGContextSetLineCap(ctx,kCGLineCapRound);
20 //对线条进行渲染
21 CGContextStrokePath(ctx);
22
23 //还原开始的时候保存的那份最纯洁的图形上下文
24 CGContextRestoreGState(ctx);
25 //第二条线
26 CGContextMoveToPoint(ctx, 40, 200);
27 CGContextAddLineToPoint(ctx, 80, 100);
28
29 //清空状态
30 // CGContextSetLineWidth(ctx, 1);
31 // [[UIColor blackColor]set];
32 // CGContextSetLineCap(ctx,kCGLineCapButt);
33
34 //渲染
35 CGContextStrokePath(ctx);
36 }
 
2.图形上下文栈机制
画第一条线的时候,会把当前的图形上下文拷贝一份保存到图形上下文栈中。
画第二条线的时候,去图形上下文栈中取出栈顶的绘图信息,作为第二条线的状态信息,第二条线的状态信息也是据此(最初保存的那份图形上下文)进行绘制。
           
注意:在栈里保存了几次,那么就可以取几次(比如不能保存了1次,取两次,在取第二次的时候,栈里为空会直接挂掉)。
 
 

iOS开发UI篇—Quartz2D使用(图形上下文栈的更多相关文章

  1. iOS开发UI篇—Quartz2D使用(图形上下文栈)

    iOS开发UI篇—Quartz2D使用(图形上下文栈) 一.qurza2d是怎么将绘图信息和绘图的属性绘制到图形上下文中去的? 说明: 新建一个项目,自定义一个view类和storyboard关联后, ...

  2. iOS开发UI篇—Quartz2D使用(绘制基本图形)

    iOS开发UI篇—Quartz2D使用(绘制基本图形) 一.简单说明 图形上下文(Graphics Context):是一个CGContextRef类型的数据 图形上下文的作用:保存绘图信息.绘图状态 ...

  3. iOS开发UI篇—Quartz2D简单介绍

    iOS开发UI篇—Quartz2D简单介绍 一.什么是Quartz2D Quartz 2D是⼀个二维绘图引擎,同时支持iOS和Mac系统 Quartz 2D能完成的工作: 绘制图形 : 线条\三角形\ ...

  4. iOS开发UI篇—Quartz2D简单使用(一)

    iOS开发UI篇—Quartz2D简单使用(一) 一.画直线 代码: // // YYlineview.m // 03-画直线 // // Created by apple on 14-6-9. // ...

  5. iOS开发UI篇—Quartz2D使用(矩阵操作)

    iOS开发UI篇—Quartz2D使用(矩阵操作) 一.关于矩阵操作 1.画一个四边形 通过设置两个端点(长和宽)来完成一个四边形的绘制. 代码: - (void)drawRect:(CGRect)r ...

  6. iOS开发UI篇—Quartz2D使用(图片剪切)

    iOS开发UI篇—Quartz2D使用(图片剪切) 一.使用Quartz2D完成图片剪切 1.把图片显示在自定义的view中 先把图片绘制到view上.按照原始大小,把图片绘制到一个点上. 代码: - ...

  7. iOS开发UI篇—Quartz2D简单使用(三)

    iOS开发UI篇—Quartz2D简单使用(三) 一.通过slider控制圆的缩放 1.实现过程 新建一个项目,新建一个继承自UIview的类,并和storyboard中自定义的view进行关联. 界 ...

  8. iOS开发UI篇—Quartz2D使用(绘图路径)

    iOS开发UI篇—Quartz2D使用(绘图路径) 一.绘图路径 A.简单说明 在画线的时候,方法的内部默认创建一个path.它把路径都放到了path里面去. 1.创建路径  cgmutablepat ...

  9. iOS开发UI篇—Quartz2D使用(截屏)

    iOS开发UI篇—Quartz2D使用(截屏) 一.简单说明 在程序开发中,有时候需要截取屏幕上的某一块内容,比如捕鱼达人游戏.如图: 完成截屏功能的核心代码:- (void)renderInCont ...

  10. iOS开发UI篇—Quartz2D简单使用(一)

    iOS开发UI篇—Quartz2D简单使用(一) 一.画直线 代码: 1 // 2 // YYlineview.m 3 // 03-画直线 4 // 5 // Created by apple on ...

随机推荐

  1. php charles 使用方法

    php charles 使用方法 打开charles 点击help菜单点击local ip address 可以获取本地ip 手机上选择代理这个ip 端口8888 然后手机访问网页 charles会弹 ...

  2. 开启docker远程访问

    开启docker远程访问 进入到/lib/systemd/system/docker.service vim /lib/systemd/system/docker.service 找到ExecStar ...

  3. 防火墙firewalld的基础操作

    防火墙Firewalld.iptables 1.systemctl模式 systemctl status firewalld #查看状态 2 systemctl start firewalld #启动 ...

  4. Python 基础之re 模块

    Python 基础之大话 re 在使用re模块中主要会用到一下几个方法: re.match() #从头匹配一个字符串 re.search() #浏览全部字符串,匹配第一个符合规则的字符串 re.fin ...

  5. avtivmq(订阅写法)

    发布-订阅消息模式与点对点模式类似,只不过在session创建消息队列时,由session.createQuene()变为session.createTopic(). 消息发布者代码: 消息订阅者代码 ...

  6. Docker学习-Spring Boot on Docker

    1.创建spring boot项目 https://start.spring.io/ pom.xml文件新增docker支持 <build> <plugins> <plu ...

  7. PHP 性能优化 - php.ini 配置

    内存 默认设置 memory_limit = 128M 单个进程可使用的内存最大值,这个值的设定可以从以下几点考虑: 应用的类型.如果是内存集中型应用,可增加该值: 单个 PHP 进程平均消耗的内存, ...

  8. PHP实现日历签到,并实现累计积分功能

    在网站开发过程中我们会经常用到签到功能来奖励用户积分,或者做一些其他活动.这次项目开发过程中做了日历签到,因为没有经验所有走了很多弯路,再次记录过程和步骤. 1.日历签到样式:使用的是calendar ...

  9. 一文看懂 K8s 日志系统设计和实践

    上一篇中我们介绍了为什么需要一个日志系统.为什么云原生下的日志系统如此重要以及云原生下日志系统的建设难点,相信DevOps.SRE.运维等同学看了是深有体会的.本篇文章单刀直入,会直接跟大家分享一下如 ...

  10. 0xe7f001f0!?NDK调试过程,无故抛出SIGSEGV。

    arm调试过程,如果抛一个SIGSEGV,地址在 0xe7f001f0 附近,原因居然是因为我在调试.当我使用n指令跳到下一行代码时,往往变成了continue指令一样地执行.还不确定地抛出SIGSE ...