iOS开发-Quartz2D上下文栈的操作&详细分析绘图本质(图形上下文栈)

来源:互联网 发布:爽肤水 面霜 知乎 编辑:程序博客网 时间:2024/04/29 01:25

1.关于图形上下文栈的操作

•将当前的上下文copy一份,保存到栈顶(那个栈叫做”图形上下文栈”)

void CGContextSaveGState(CGContextRef c)

•将栈顶的上下文出栈,替换掉当前的上下文

void CGContextRestoreGState(CGContextRef c)

2.用实例说明图形上下文栈的好处

2.1先创建一个project,然后自定义一个view,并且让这个自定义的view成为控制器的view



2.2.用代码创建两根线运行结果如下



代码
#import "MJView.h"@implementation MJView- (id)initWithFrame:(CGRect)frame{    self = [super initWithFrame:frame];    if (self) {        // Initialization code    }    return self;}- (void)drawRect:(CGRect)rect{    // 1.获得上下文    CGContextRef ctx = UIGraphicsGetCurrentContext();               // 设置绘图状态    CGContextSetLineWidth(ctx, 10);    [[UIColor redColor] set];    CGContextSetLineCap(ctx, kCGLineCapRound); //设置画线的首位为圆状        // 第1根线    CGContextMoveToPoint(ctx, 50, 50);    CGContextAddLineToPoint(ctx, 120, 190);    //渲染    CGContextStrokePath(ctx);    <pre code_snippet_id="643034" snippet_file_name="blog_20150413_1_8397810" name="code" class="objc">     // 设置绘图状态    CGContextSetLineWidth(ctx, 10);    [[UIColor redColor] set];    CGContextSetLineCap(ctx, kCGLineCapRound); //设置画线的首位为圆状
// 第2根线 CGContextMoveToPoint(ctx, 10, 70); CGContextAddLineToPoint(ctx, 220, 290); //渲染 CGContextStrokePath(ctx);// CGContextDrawPath(ctx, kCGPathStroke); 渲染也可以用这种方式(前面参数为上下文,后面参数为枚举可确定渲染方式}@end

2.3需求,要让右边的那根线不要拥有右边那根线的样式,一切还原(也就是让第二根线不受第一根线设置的状态的影响)

分析一:
为第二根线设置状态覆盖掉第一根线的状态,可以实现,但是很费力,假设有很多线,就必须要写很多代码才能覆盖完毕
分析二:
•将当前的上下文copy一份,保存到栈顶(那个栈叫做”图形上下文栈”)

void CGContextSaveGState(CGContextRef c)

•将栈顶的上下文出栈,替换掉当前的上下文

void CGContextRestoreGState(CGContextRef c)

则本项目中要实现为在代码中增加两行代码

    // 1.获得上下文

    CGContextRef ctx =UIGraphicsGetCurrentContext();

    // 2.将栈顶的上下文出栈,替换当前的上下文

    CGContextRestoreGState(ctx);

2.3.1运行结果如下

代码
////  MJView.m#import "MJView.h"@implementation MJView- (id)initWithFrame:(CGRect)frame{    self = [super initWithFrame:frame];    if (self) {        // Initialization code    }    return self;}- (void)drawRect:(CGRect)rect{    // 1.获得上下文    CGContextRef ctx = UIGraphicsGetCurrentContext();        // 将ctx拷贝一份放到栈中    CGContextSaveGState(ctx);        // 设置绘图状态    CGContextSetLineWidth(ctx, 10);    [[UIColor redColor] set];    CGContextSetLineCap(ctx, kCGLineCapRound); //设置画线的首位为圆状        // 第1根线    CGContextMoveToPoint(ctx, 50, 50);    CGContextAddLineToPoint(ctx, 120, 190);    //渲染    CGContextStrokePath(ctx);        // 将栈顶的上下文出栈,替换当前的上下文    CGContextRestoreGState(ctx);            // 第2根线    CGContextMoveToPoint(ctx, 10, 70);    CGContextAddLineToPoint(ctx, 220, 290);    //渲染    CGContextStrokePath(ctx);//    CGContextDrawPath(ctx, kCGPathStroke);  渲染也可以用这种方式(前面参数为上下文,后面参数为枚举可确定渲染方式}@end



3.详细分析绘图本质(图形上下文栈)

对如下代码作分析

- (void)drawRect:(CGRect)rect

{

    // 1.获得上下文

    CGContextRef ctx =UIGraphicsGetCurrentContext();

    

    // 设置绘图状态

    CGContextSetLineWidth(ctx,10);

    [[UIColorredColor]set];

    CGContextSetLineCap(ctx,kCGLineCapRound);//设置画线的首位为圆状

    

    //1根线(这个路径暂时添加到上下文对象中)

    CGContextMoveToPoint(ctx,50,50);

    CGContextAddLineToPoint(ctx,120,190);

    //渲染(把当前上下文保存的所有路径都一次性渲染到view上面)

     CGContextStrokePath(ctx);

    

  

    // 2根线


    CGContextMoveToPoint(ctx,10,70);

    CGContextAddLineToPoint(ctx,220,290);

   //渲染

    CGContextStrokePath(ctx);

//    CGContextDrawPath(ctx, kCGPathStroke);  

}


内存首先有一个view(画板)如右图

然后有一个上下文对象如左图(保存绘图路径、绘图状态以及绘图到哪里去) 

执行如下代码后内存为下面这样的状态

  CGContextRef ctx =UIGraphicsGetCurrentContext();

    

    // ctx拷贝一份放到栈中

    CGContextSaveGState(ctx);

    

    // 设置绘图状态

    CGContextSetLineWidth(ctx,10);

    [[UIColorredColor]set];

    CGContextSetLineCap(ctx,kCGLineCapRound);//设置画线的首位为圆状

    

    //1根线(这个路径暂时添加到上下文对象中)

    CGContextMoveToPoint(ctx,50,50);

    CGContextAddLineToPoint(ctx,120,190);

  Pasted Graphic 1.tiff

接着执行下面一行代码后内存为下面的状态

//渲染(把当前上下文保存的所有路径都一次性渲染到view上面)

    CGContextStrokePath(ctx);


Pasted Graphic 2.tiff

   当执行下面几行代码后内存为如下的状态

// 2根线

    CGContextMoveToPoint(ctx,10,70);

    CGContextAddLineToPoint(ctx,220,290);

Pasted Graphic 3.tiff

执行下面代码后内存为如下图

//渲染

    CGContextStrokePath(ctx);


Pasted Graphic 4.tiff





思路一:

完整代码为

- (void)drawRect:(CGRect)rect

{

    // 1.获得上下文

    CGContextRef ctx =UIGraphicsGetCurrentContext();

    

    // 设置绘图状态

    CGContextSetLineWidth(ctx,10);

    [[UIColorredColor]set];

    CGContextSetLineCap(ctx,kCGLineCapRound);//设置画线的首位为圆状

    

    //1根线(这个路径暂时添加到上下文对象中)

    CGContextMoveToPoint(ctx,50,50);

    CGContextAddLineToPoint(ctx,120,190);

    //渲染(把当前上下文保存的所有路径都一次性渲染到view上面)

     CGContextStrokePath(ctx);

    

  

    // 2根线

// 设置绘图状态

    CGContextSetLineWidth(ctx,1);

    [[UIColorblackColor]set];

    CGContextSetLineCap(ctx,kCGLineCapbutt);        CGContextMoveToPoint(ctx,10,70);

    CGContextAddLineToPoint(ctx,220,290);

   //渲染

    CGContextStrokePath(ctx);

//    CGContextDrawPath(ctx, kCGPathStroke);  

}


也就是在画第二根线的时候增加如下代码把上下文状态覆盖掉

// 设置绘图状态

    CGContextSetLineWidth(ctx,1);

    [[UIColorblackColor]set];

    CGContextSetLineCap(ctx,kCGLineCapbutt); 

这个时候内存状态为:

Pasted Graphic 5.tiff

当执行下面代码后内存为

    CGContextMoveToPoint(ctx, 10,70);

    CGContextAddLineToPoint(ctx,220,290);

Pasted Graphic 6.tiff

当对第二根线渲染后

CGContextStrokePath(ctx);


Pasted Graphic 7.tiff





思路二:

思路一可以实现但是很麻烦,假设第一根线有很多状态就必须要再写很多状态来覆盖掉才行,所有这就采用图形上下文栈


此时完成代码为:

- (void)drawRect:(CGRect)rect

{

    // 1.获得上下文

    CGContextRef ctx =UIGraphicsGetCurrentContext();

    

    // ctx拷贝一份放到栈中

    CGContextSaveGState(ctx);

    

    // 设置绘图状态

    CGContextSetLineWidth(ctx,10);

    [[UIColorredColor]set];

    CGContextSetLineCap(ctx,kCGLineCapRound);//设置画线的首位为圆状

    

    //1根线(这个路径暂时添加到上下文对象中)

    CGContextMoveToPoint(ctx,50,50);

    CGContextAddLineToPoint(ctx,120,190);

    //渲染(把当前上下文保存的所有路径都一次性渲染到view上面)

    CGContextStrokePath(ctx);

    

    //将栈顶的上下文出栈,替换当前的上下文

    CGContextRestoreGState(ctx);

    

    

    // 2根线

    CGContextMoveToPoint(ctx,10,70);

    CGContextAddLineToPoint(ctx,220,290);

   //渲染

    CGContextStrokePath(ctx);

//    CGContextDrawPath(ctx, kCGPathStroke);  渲染也可以用这种方式(前面参数为上下文,后面参数为枚举可确定渲染方式

}


当执行如下代码后,就会把内存中得存放图形上下文对象(中间)拷贝一份到栈当中(左图)

// ctx拷贝一份放到栈中

    CGContextSaveGState(ctx);

    


Pasted Graphic 8.tiff

当执行如下代码后内存状态为


    // 设置绘图状态

    CGContextSetLineWidth(ctx,10);

    [[UIColorredColor]set];

    CGContextSetLineCap(ctx,kCGLineCapRound);//设置画线的首位为圆状

    

    //1根线(这个路径暂时添加到上下文对象中)

    CGContextMoveToPoint(ctx,50,50);

    CGContextAddLineToPoint(ctx,120,190);

Pasted Graphic 9.tiff

当执行下面代码后内存状态为

//渲染(把当前上下文保存的所有路径都一次性渲染到view上面)

    CGContextStrokePath(ctx);

Pasted Graphic 10.tiff

执行如下代码后内存状态为下图,也就是把保存在栈顶得上下文出栈替换掉第一根线的上下文)这个时候画第二根线的时候,其上下文状态就完全不受到第二根线的影响


  //将栈顶的上下文出栈,替换当前的上下文

    CGContextRestoreGState(ctx);

Pasted Graphic 11.tiff


0 0
原创粉丝点击