服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

2020-12-30 13:25文顶顶 IOS

这篇文章主要介绍了iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法,代码基于传统的Objective-C,需要的朋友可以参考下

上下文栈

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

说明:

新建一个项目,自定义一个view类和storyboard关联后,重写该类中的drowrect方法。
画线的三个步骤:
(1)获取上下文
(2)绘图
(3)渲染
要求:画两条单独的线
代码和效果图:

 

复制代码 代码如下:


- (void)drawrect:(cgrect)rect
{
    //获取上下文
    cgcontextref ctx=uigraphicsgetcurrentcontext();
    //绘图
    //第一条线
    cgcontextmovetopoint(ctx, 20, 100);
    cgcontextaddlinetopoint(ctx, 100, 320);
   
    //第二条线
    cgcontextmovetopoint(ctx, 40, 200);
    cgcontextaddlinetopoint(ctx, 80, 100);
    //渲染
    cgcontextstrokepath(ctx);
   
}

 

 


效果图:

 

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

设置线段的宽度:两头为圆形,颜色等。
代码和效果图(发现第二条线也被渲染成第一条线的样式和状态)

复制代码 代码如下:


- (void)drawrect:(cgrect)rect
{
    //获取上下文
    cgcontextref ctx=uigraphicsgetcurrentcontext();
    //绘图
    //第一条线
    cgcontextmovetopoint(ctx, 20, 100);
    cgcontextaddlinetopoint(ctx, 100, 320);
   
    //设置第一条线的状态
    //设置线条的宽度
    cgcontextsetlinewidth(ctx, 12);
    //设置线条的颜色
    [[uicolor browncolor]set];
    //设置线条两端的样式为圆角
    cgcontextsetlinecap(ctx,kcglinecapround);
    //对线条进行渲染
    cgcontextstrokepath(ctx);
   
    //第二条线
    cgcontextmovetopoint(ctx, 40, 200);
    cgcontextaddlinetopoint(ctx, 80, 100);
    //渲染
    cgcontextstrokepath(ctx);
   
}

 

 


效果图:

 

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

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

第一种做法:
在对第二条线进行设置的时候,清空它的状态

 

复制代码 代码如下:


- (void)drawrect:(cgrect)rect
{
    //获取上下文
    cgcontextref ctx=uigraphicsgetcurrentcontext();
    //绘图
    //第一条线
    cgcontextmovetopoint(ctx, 20, 100);
    cgcontextaddlinetopoint(ctx, 100, 320);
   
    //设置第一条线的状态
    //设置线条的宽度
    cgcontextsetlinewidth(ctx, 12);
    //设置线条的颜色
    [[uicolor browncolor]set];
    //设置线条两端的样式为圆角
    cgcontextsetlinecap(ctx,kcglinecapround);
    //对线条进行渲染
    cgcontextstrokepath(ctx);
   
    //第二条线
    cgcontextmovetopoint(ctx, 40, 200);
    cgcontextaddlinetopoint(ctx, 80, 100);
   
    //清空状态
    cgcontextsetlinewidth(ctx, 1);
    [[uicolor blackcolor]set];
    cgcontextsetlinecap(ctx,kcglinecapbutt);
   
    //渲染
    cgcontextstrokepath(ctx);
   
}

 

 


第二种做法:
把第一条线从开始绘制到渲染的代码剪切到第二条线渲染完成之后,这样先绘制并渲染了第一条线,该线并没有对绘制信息进行过设置,显示出来的第二条线即位系统默认的效果。

 

 

复制代码 代码如下:


- (void)drawrect:(cgrect)rect
{
    //获取上下文
    cgcontextref ctx=uigraphicsgetcurrentcontext();
    //绘图
   
    //第二条线
    cgcontextmovetopoint(ctx, 40, 200);
    cgcontextaddlinetopoint(ctx, 80, 100);
   
    //清空状态
    //    cgcontextsetlinewidth(ctx, 1);
    //    [[uicolor blackcolor]set];
   
    //    cgcontextsetlinecap(ctx,kcglinecapbutt);
   
    //渲染
    cgcontextstrokepath(ctx);
   
    //第一条线
    cgcontextmovetopoint(ctx, 20, 100);
    cgcontextaddlinetopoint(ctx, 100, 320);
   
    //设置第一条线的状态
    //设置线条的宽度
    cgcontextsetlinewidth(ctx, 12);
    //设置线条的颜色
    [[uicolor browncolor]set];
    //设置线条两端的样式为圆角
    cgcontextsetlinecap(ctx,kcglinecapround);
    //对线条进行渲染
    cgcontextstrokepath(ctx);
}

 

 


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

 

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

但是有的情况下,必须要先画第一条线再画第二条线,要求在交叉部分,第二条线盖在第一条线的上面。如果要求是这样,那么只能使用第一种做法,但是如果现在有新的需求,要求在这个基础上再画两条线,那就需要清空ctx中的状态很多次,很麻烦。为了解决这个问题,下面给大家介绍图形上下文栈。
 
二、绘图的完整过程
程序启动,显示自定义的view。当程序第一次显示在我们眼前的时候,程序会调用drawrect:方法,在里面获取了图形上下文(在内存中拥有了),然后利用图形上下文保存绘图信息,可以理解为图形上下文中有一块区域用来保存绘图信息,有一块区域用来保存绘图的状态(线宽,圆角,颜色)。直线不是直接绘制到view上的,可以理解为在图形上下文中有一块单独的区域用来先绘制图形,当调用渲染方法的时候,再把绘制好的图形显示到view上去。
 
在绘制图形区域,会去保存绘图状态区域中查找对应的状态信息(线宽,圆角,颜色),然后在绘图区域把对第一条直线绘制完成。其实在渲染之前,就已经把直线在绘制图形区域画好了。
如图:

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

说明:这些示意图和本文中的程序代码块,不具备一一对应关系,只是为了说明绘图的完整过程。
调用渲染方法的时候,把绘制图形区域已经画好的图形直接显示到view上,就是我们看到的样子了。
如图:

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

画第二条的时候,如果没有对绘图状态进行重新设置,那么可以发现画第一天线的时候使用的绘图状态还保存在图形上下文中,在第二条线进行渲染之前,会根据第一条线(上一份绘图状态)对第二条线进行相应的设置,渲染后把第二条线显示到屏幕上。
参考代码:

 

复制代码 代码如下:


- (void)drawrect:(cgrect)rect
{
    //获取上下文
    cgcontextref ctx=uigraphicsgetcurrentcontext();
    //绘图
    //第一条线
    cgcontextmovetopoint(ctx, 20, 100);
    cgcontextaddlinetopoint(ctx, 100, 320);
   
    //设置第一条线的状态
    //设置线条的宽度
    cgcontextsetlinewidth(ctx, 12);
    //设置线条的颜色
    [[uicolor browncolor]set];
    //设置线条两端的样式为圆角
    cgcontextsetlinecap(ctx,kcglinecapround);
    //对线条进行渲染
    cgcontextstrokepath(ctx);
   
    //第二条线
    cgcontextmovetopoint(ctx, 40, 200);
    cgcontextaddlinetopoint(ctx, 80, 100);
    //渲染
    cgcontextstrokepath(ctx);
}

 

 


如果清空了状态,则在渲染之前,在绘制图形区域对第二条线进行绘制的时候,会去查找当前的绘图信息(已经更改——清空),根据绘图信息对第二条线进行绘制,调用渲染方法的时候把第二条线显示到view上。
参考代码:

 

 

复制代码 代码如下:


- (void)drawrect:(cgrect)rect
{
    //获取上下文
    cgcontextref ctx=uigraphicsgetcurrentcontext();
    //绘图
    //第一条线
    cgcontextmovetopoint(ctx, 20, 100);
    cgcontextaddlinetopoint(ctx, 100, 320);
   
    //设置第一条线的状态
    //设置线条的宽度
    cgcontextsetlinewidth(ctx, 12);
    //设置线条的颜色
    [[uicolor browncolor]set];
    //设置线条两端的样式为圆角
    cgcontextsetlinecap(ctx,kcglinecapround);
    //对线条进行渲染
    cgcontextstrokepath(ctx);
   
    //第二条线
    cgcontextmovetopoint(ctx, 40, 200);
    cgcontextaddlinetopoint(ctx, 80, 100);
   
    //清空状态
    cgcontextsetlinewidth(ctx, 1);
    [[uicolor blackcolor]set];
    cgcontextsetlinecap(ctx,kcglinecapbutt);
   
    //渲染
    cgcontextstrokepath(ctx);
}

 

 

 

三、图形上下文栈
1.简单说明
在获取图形上下文之后,通过 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);
}

 

 

 

2.图形上下文栈机制
画第一条线的时候,会把当前的图形上下文拷贝一份保存到图形上下文栈中。
iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

画第二条线的时候,去图形上下文栈中取出栈顶的绘图信息,作为第二条线的状态信息,第二条线的状态信息也是据此(最初保存的那份图形上下文)进行绘制。

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

注意:在栈里保存了几次,那么就可以取几次(比如不能保存了1次,取两次,在取第二次的时候,栈里为空会直接挂掉)。

矩阵操作
一、关于矩阵操作
1.画一个四边形
通过设置两个端点(长和宽)来完成一个四边形的绘制。
代码:

 

复制代码 代码如下:


- (void)drawrect:(cgrect)rect
{
    //画四边形
    //获取图形上下文
    cgcontextref ctx=uigraphicsgetcurrentcontext();
    //绘图
    cgcontextaddrect(ctx, cgrectmake(20, 50, 100, 100));
    //渲染
    cgcontextstrokepath(ctx);
}

 

 


说明:通过这种方式画矩形有弱点:画出来的矩形永远都是正的。如下图:

 

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

2.画一个歪的四边形
如何画一个歪的矩形?(通过矩阵操作来完成,和形变操作相似)
可以通过矩阵操作,把画出来的东西进行形变(旋转,缩放,平移)
方法:cgcontextrotatectm(<#cgcontextref c#>, <#cgfloat angle#>)该接受两个参数(图形上下文,弧度)
注意点:设置矩阵操作必须要在添加图形之前,如果设置在添加图形之后的话,此时它已经画完了,无效。
代码:

 

复制代码 代码如下:


- (void)drawrect:(cgrect)rect
{
    //画四边形
    //获取图形上下文
    cgcontextref ctx=uigraphicsgetcurrentcontext();
    //矩阵操作
    //注意点:设置矩阵操作必须要在添加绘图信息之前
    //旋转45度
    cgcontextrotatectm(ctx, m_pi_4);
   
    //绘图
    cgcontextaddrect(ctx, cgrectmake(150, 100, 100, 100));
    //渲染
    cgcontextstrokepath(ctx);
}

 

 


效果:

 

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

二、关于旋转
1.旋转演示
view之所以能够显示视图,是因为它的上面有layer,将来图形也是渲染到layer上面。
且,旋转的时候是整个layer都旋转了,可以再画一个圆进行验证。
代码1(未旋转):

 

复制代码 代码如下:


- (void)drawrect:(cgrect)rect
{
    //获取图形上下文
    cgcontextref ctx=uigraphicsgetcurrentcontext();
    //矩阵操作
    //注意点:设置矩阵操作必须要在添加绘图信息之前
    //旋转45度
    //    cgcontextrotatectm(ctx, m_pi_4);
   
    //绘图
    //画四边形
    cgcontextaddrect(ctx, cgrectmake(150, 100, 100, 100));
    //画一个圆
    cgcontextaddellipseinrect(ctx, cgrectmake(200, 200, 50, 50));
    //渲染
    cgcontextstrokepath(ctx);
}

 

 


 效果:

 

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

代码2(旋转):

 

复制代码 代码如下:


- (void)drawrect:(cgrect)rect
{
    //获取图形上下文
    cgcontextref ctx=uigraphicsgetcurrentcontext();
    //矩阵操作
    //注意点:设置矩阵操作必须要在添加绘图信息之前
    //旋转45度
    cgcontextrotatectm(ctx, m_pi_4);
   
    //绘图
    //画四边形
    cgcontextaddrect(ctx, cgrectmake(150, 100, 100, 100));
    //画一个圆
    cgcontextaddellipseinrect(ctx, cgrectmake(200, 200, 50, 50));
    //渲染
    cgcontextstrokepath(ctx);
}

 

 


效果:

 

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

2.关于旋转的补充说明
提示:旋转的时候,是整个layer都旋转了。

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

三、缩放
方法:cgcontextscalectm(<#cgcontextref c#>, <#cgfloat sx#>, <#cgfloat sy#>)
该方法接收三个参数(图形上下文,x方向的缩放比例,y方向上的缩放比例
代码示例:

 

复制代码 代码如下:


- (void)drawrect:(cgrect)rect
{
    //获取图形上下文
    cgcontextref ctx=uigraphicsgetcurrentcontext();
    //矩阵操作
    //注意点:设置矩阵操作必须要在添加绘图信息之前
    //缩放,x方向缩放0.5倍,y方向缩放1.5倍
    cgcontextscalectm(ctx, 0.5, 1.5);
   
    //绘图
    //画四边形
    cgcontextaddrect(ctx, cgrectmake(150, 100, 100, 100));
    //画一个圆
    cgcontextaddellipseinrect(ctx, cgrectmake(200, 200, 50, 50));
    //渲染
    cgcontextstrokepath(ctx);
}

 

 


效果:

 

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

四、平移
方法: cgcontexttranslatectm(<#cgcontextref c#>, <#cgfloat tx#>, <#cgfloat ty#>)
该方法接收三个参数(图形上下文,x方向的偏移量,y方向上的偏移量)  
代码示例:

 

复制代码 代码如下:


- (void)drawrect:(cgrect)rect
{
    //获取图形上下文
    cgcontextref ctx=uigraphicsgetcurrentcontext();
    //矩阵操作
    //注意点:设置矩阵操作必须要在添加绘图信息之前
    //平移,x方向移动50,y方向移动100
    cgcontexttranslatectm(ctx, 50, 100);
   
    //绘图
    //画四边形
    cgcontextaddrect(ctx, cgrectmake(150, 100, 100, 100));
    //画一个圆
    cgcontextaddellipseinrect(ctx, cgrectmake(200, 200, 50, 50));
    //渲染
    cgcontextstrokepath(ctx);
}

 

 


效果:

 

iOS开发中使用Quartz2D绘制上下文栈和矩阵的方法

提示:坐标原点为view的左上角。

延伸 · 阅读

精彩推荐
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25