[iOS]上下文的理解

来源:互联网 发布:电信网络诈骗定什么罪 编辑:程序博客网 时间:2024/05/17 02:49

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

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

void CGContextSaveGState(CGContextRef c)

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

void CGContextRestoreGState(CGContextRef c)

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

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



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



代码
[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #import "MJView.h"  
  2.   
  3. @implementation MJView  
  4.   
  5. - (id)initWithFrame:(CGRect)frame  
  6. {  
  7.     self = [super initWithFrame:frame];  
  8.     if (self) {  
  9.         // Initialization code  
  10.     }  
  11.     return self;  
  12. }  
  13.   
  14. - (void)drawRect:(CGRect)rect  
  15. {  
  16.     // 1.获得上下文  
  17.     CGContextRef ctx = UIGraphicsGetCurrentContext();  
  18.       
  19.      
  20.       
  21.     // 设置绘图状态  
  22.     CGContextSetLineWidth(ctx, 10);  
  23.     [[UIColor redColor] set];  
  24.     CGContextSetLineCap(ctx, kCGLineCapRound); //设置画线的首位为圆状  
  25.       
  26.     // 第1根线  
  27.     CGContextMoveToPoint(ctx, 5050);  
  28.     CGContextAddLineToPoint(ctx, 120190);  
  29.     //渲染  
  30.     CGContextStrokePath(ctx);  
  31.       
  32. <pre code_snippet_id="643034" snippet_file_name="blog_20150413_1_8397810" name="code" class="objc">     // 设置绘图状态  
  33.     CGContextSetLineWidth(ctx, 10);  
  34.     [[UIColor redColor] set];  
  35.     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运行结果如下

代码
[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //  
  2. //  MJView.m  
  3.   
  4.   
  5. #import "MJView.h"  
  6.   
  7. @implementation MJView  
  8.   
  9. - (id)initWithFrame:(CGRect)frame  
  10. {  
  11.     self = [super initWithFrame:frame];  
  12.     if (self) {  
  13.         // Initialization code  
  14.     }  
  15.     return self;  
  16. }  
  17.   
  18. - (void)drawRect:(CGRect)rect  
  19. {  
  20.     // 1.获得上下文  
  21.     CGContextRef ctx = UIGraphicsGetCurrentContext();  
  22.       
  23.     // 将ctx拷贝一份放到栈中  
  24.     CGContextSaveGState(ctx);  
  25.       
  26.     // 设置绘图状态  
  27.     CGContextSetLineWidth(ctx, 10);  
  28.     [[UIColor redColor] set];  
  29.     CGContextSetLineCap(ctx, kCGLineCapRound); //设置画线的首位为圆状  
  30.       
  31.     // 第1根线  
  32.     CGContextMoveToPoint(ctx, 5050);  
  33.     CGContextAddLineToPoint(ctx, 120190);  
  34.     //渲染  
  35.     CGContextStrokePath(ctx);  
  36.       
  37.     // 将栈顶的上下文出栈,替换当前的上下文  
  38.     CGContextRestoreGState(ctx);  
  39.       
  40.       
  41.     // 第2根线  
  42.     CGContextMoveToPoint(ctx, 1070);  
  43.     CGContextAddLineToPoint(ctx, 220290);  
  44.     //渲染  
  45.     CGContextStrokePath(ctx);  
  46. //    CGContextDrawPath(ctx, kCGPathStroke);  渲染也可以用这种方式(前面参数为上下文,后面参数为枚举可确定渲染方式  
  47. }  
  48.   
  49. @end  



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

对如下代码作分析

- (void)drawRect:(CGRect)rect

{

    // 1.获得上下文

    CGContextRef ctx =UIGraphicsGetCurrentContext();

    

    // 设置绘图状态

    CGContextSetLineWidth(ctx,10);

    [[UIColorredColorset];

    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);

    [[UIColorredColorset];

    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);

    [[UIColorredColorset];

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

    

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

    CGContextMoveToPoint(ctx,50,50);

    CGContextAddLineToPoint(ctx,120,190);

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

     CGContextStrokePath(ctx);

    

  

    // 2根线

// 设置绘图状态

    CGContextSetLineWidth(ctx,1);

    [[UIColorblackColorset];

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

    CGContextAddLineToPoint(ctx,220,290);

   //渲染

    CGContextStrokePath(ctx);

//    CGContextDrawPath(ctx, kCGPathStroke);  

}


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

// 设置绘图状态

    CGContextSetLineWidth(ctx,1);

    [[UIColorblackColorset];

    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);

    [[UIColorredColorset];

    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);

    [[UIColorredColorset];

    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
原创粉丝点击