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

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

说明:

新建一个项目,自定义一个view类和storyboard关联后,重写该类中的drowrect方法。
画线的三个步骤:
(1)获取上下文
(2)绘图
(3)渲染
要求:画两条单独的线
代码和效果图:
 - (void)drawRect:(CGRect)rect
{
//获取上下文
CGContextRef ctx=UIGraphicsGetCurrentContext();
//绘图
//第一条线
CGContextMoveToPoint(ctx, , );
CGContextAddLineToPoint(ctx, , ); //第二条线
CGContextMoveToPoint(ctx, , );
CGContextAddLineToPoint(ctx, , );
//渲染
CGContextStrokePath(ctx); }
效果图:
设置线段的宽度:两头为圆形,颜色等。
代码和效果图(发现第二条线也被渲染成第一条线的样式和状态)
 - (void)drawRect:(CGRect)rect
{
//获取上下文
CGContextRef ctx=UIGraphicsGetCurrentContext();
//绘图
//第一条线
CGContextMoveToPoint(ctx, , );
CGContextAddLineToPoint(ctx, , ); //设置第一条线的状态
//设置线条的宽度
CGContextSetLineWidth(ctx, );
//设置线条的颜色
[[UIColor brownColor]set];
//设置线条两端的样式为圆角
CGContextSetLineCap(ctx,kCGLineCapRound);
//对线条进行渲染
CGContextStrokePath(ctx); //第二条线
CGContextMoveToPoint(ctx, , );
CGContextAddLineToPoint(ctx, , );
//渲染
CGContextStrokePath(ctx); }

效果图:

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

第一种做法:
在对第二条线进行设置的时候,清空它的状态
 - (void)drawRect:(CGRect)rect
{
//获取上下文
CGContextRef ctx=UIGraphicsGetCurrentContext();
//绘图
//第一条线
CGContextMoveToPoint(ctx, , );
CGContextAddLineToPoint(ctx, , ); //设置第一条线的状态
//设置线条的宽度
CGContextSetLineWidth(ctx, );
//设置线条的颜色
[[UIColor brownColor]set];
//设置线条两端的样式为圆角
CGContextSetLineCap(ctx,kCGLineCapRound);
//对线条进行渲染
CGContextStrokePath(ctx); //第二条线
CGContextMoveToPoint(ctx, , );
CGContextAddLineToPoint(ctx, , ); //清空状态
CGContextSetLineWidth(ctx, );
[[UIColor blackColor]set];
CGContextSetLineCap(ctx,kCGLineCapButt); //渲染
CGContextStrokePath(ctx); }
 
第二种做法:
把第一条线从开始绘制到渲染的代码剪切到第二条线渲染完成之后,这样先绘制并渲染了第一条线,该线并没有对绘制信息进行过设置,显示出来的第二条线即位系统默认的效果。
 - (void)drawRect:(CGRect)rect
{
//获取上下文
CGContextRef ctx=UIGraphicsGetCurrentContext();
//绘图 //第二条线
CGContextMoveToPoint(ctx, , );
CGContextAddLineToPoint(ctx, , ); //清空状态
// CGContextSetLineWidth(ctx, 1);
// [[UIColor blackColor]set]; // CGContextSetLineCap(ctx,kCGLineCapButt); //渲染
CGContextStrokePath(ctx); //第一条线
CGContextMoveToPoint(ctx, , );
CGContextAddLineToPoint(ctx, , ); //设置第一条线的状态
//设置线条的宽度
CGContextSetLineWidth(ctx, );
//设置线条的颜色
[[UIColor brownColor]set];
//设置线条两端的样式为圆角
CGContextSetLineCap(ctx,kCGLineCapRound);
//对线条进行渲染
CGContextStrokePath(ctx);
}

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

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

CGContextSaveGState(ctx);

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

在画第二条线之前,使用CGContextRestoreGState(ctx);方法,还原开始的时候保存的那份最纯洁的图形上下文。
代码:
 - (void)drawRect:(CGRect)rect
{
//获取上下文
CGContextRef ctx=UIGraphicsGetCurrentContext();
//保存一份最初的图形上下文
CGContextSaveGState(ctx); //绘图
//第一条线
CGContextMoveToPoint(ctx, , );
CGContextAddLineToPoint(ctx, , ); //设置第一条线的状态
//设置线条的宽度
CGContextSetLineWidth(ctx, );
//设置线条的颜色
[[UIColor brownColor]set];
//设置线条两端的样式为圆角
CGContextSetLineCap(ctx,kCGLineCapRound);
//对线条进行渲染
CGContextStrokePath(ctx); //还原开始的时候保存的那份最纯洁的图形上下文
CGContextRestoreGState(ctx);
//第二条线
CGContextMoveToPoint(ctx, , );
CGContextAddLineToPoint(ctx, , ); //清空状态
// CGContextSetLineWidth(ctx, 1);
// [[UIColor blackColor]set];
// CGContextSetLineCap(ctx,kCGLineCapButt); //渲染
CGContextStrokePath(ctx);
}
 
2.图形上下文栈机制
画第一条线的时候,会把当前的图形上下文拷贝一份保存到图形上下文栈中。
画第二条线的时候,去图形上下文栈中取出栈顶的绘图信息,作为第二条线的状态信息,第二条线的状态信息也是据此(最初保存的那份图形上下文)进行绘制。
           
注意:在栈里保存了几次,那么就可以取几次(比如不能保存了1次,取两次,在取第二次的时候,栈里为空会直接挂掉)。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. POJ - 3652 Persistent Bits

    “模拟”类型,题型容易,使用bitset库对二进制逐位操作,初始化.十进制转二进制(unsigned int).位操作. POJ - 3652 Persistent Bits Time Limit:  ...

  2. Fragment的隐藏与显示

    package com.bwie.helpdemo; import com.bwie.fragment.BillFrag; import com.bwie.fragment.IndexFrag; im ...

  3. Redis的简介与安装

    1.简介 Redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted ...

  4. 前端开发面试题JS2

    21.如何判断一个对象是否属于某个类? 使用instanceof if(a instanceof Person){ alert('yes'); } 22.new操作符具体干了什么呢? (1)创建一个空 ...

  5. 转 java中的session

    书中讲:以下情况,Session结束生命周期,Servlet容器将Session所占资源释放:1.客户端关闭浏览器2.Session过期3.服务器端调用了HttpSession的invalidate( ...

  6. Jenkins入门系列之——01第一章 Jenkins是什么?

    第一章 Jenkins是什么? Jenkins 是一个可扩展的持续集成引擎. 主要用于: l 持续.自动地构建/测试软件项目. l 监控一些定时执行的任务. Jenkins拥有的特性包括: l 易于安 ...

  7. apache和tomcat有什么不同,为什么要整合apache 和tomcat?

    1. Apache是web服务器,Tomcat是应用(java)服务器,它只是一个servlet容器,是Apache的扩展.2. Apache和Tomcat都可以做为独立的web服务器来运行,但是Ap ...

  8. javascript 设计模式1----单例模式

    定义:保证一个类仅有一个实例,并提供一个访问的全局接口: 就是收:当我们 var a = new a(); var a1 = new a()是:a与a1是相等的.怎么实现呢,就是第一次实例化.第二不在 ...

  9. SQL 向上取整、向下取整、四舍五入取整的实例!round、rounddown、roundup

    sql server ==================================================== [四舍五入取整截取] select round(54.56,0) === ...

  10. c# this关键字的理解

    this关键字引用类的当前实例 1/限定被相似的名称隐藏的成员 2/将对象作为参数传递到其他方法 3/声明索引器 实际案例参考: //成员类 public class Employee { priva ...