一、绘图的完整过程
程序启动,显示自定义的view。当程序第一次显示在我们眼前的时候,程序会调用drawRect:方法,在里面获取了图形上下文(在内存中拥有了),然后利用图形上下文保存绘图信息,可以理解为图形上下文中有一块区域用来保存绘图信息,有一块区域用来保存绘图的状态(线宽,圆角,颜色)。直线不是直接绘制到view上的,可以理解为在图形上下文中有一块单独的区域用来先绘制图形,当调用渲染方法的时候,再把绘制好的图形显示到view上去。
在绘制图形区域,会去保存绘图状态区域中查找对应的状态信息(线宽,圆角,颜色),然后在绘图区域把对第一条直线绘制完成。其实在渲染之前,就已经把直线在绘制图形区域画好了。
如图:
![](https://images0.cnblogs.com/i/450136/201406/111742206708132.png)
![](https://images0.cnblogs.com/i/450136/201406/111743028272387.png)
说明:这些示意图和本文中的程序代码块,不具备一一对应关系,只是为了说明绘图的完整过程。
调用渲染方法的时候,把绘制图形区域已经画好的图形直接显示到view上,就是我们看到的样子了。
如图:
![](https://images0.cnblogs.com/i/450136/201406/111745272335536.png)
![](https://images0.cnblogs.com/i/450136/201406/111745538744931.png)
画第二条的时候,如果没有对绘图状态进行重新设置,那么可以发现画第一天线的时候使用的绘图状态还保存在图形上下文中,在第二条线进行渲染之前,会根据第一条线(上一份绘图状态)对第二条线进行相应的设置,渲染后把第二条线显示到屏幕上。
参考代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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上。
参考代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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);方法,还原开始的时候保存的那份最纯洁的图形上下文。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 - (void)drawRect:(CGRect)rect 2 { 3 // 1.获得上下文 4 CGContextRef ctx = UIGraphicsGetCurrentContext(); 5 6 // 将ctx拷贝一份放到栈中 7 CGContextSaveGState(ctx); 8 9 // 设置绘图状态 10 CGContextSetLineWidth(ctx, 10); 11 [[UIColor redColor] set]; 12 CGContextSetLineCap(ctx, kCGLineCapRound); 13 14 // 第1根线 15 CGContextMoveToPoint(ctx, 50, 50); 16 CGContextAddLineToPoint(ctx, 120, 190); 17 18 CGContextStrokePath(ctx); 19 20 // 将栈顶的上下文出栈,替换当前的上下文 21 CGContextRestoreGState(ctx); 22 23 24 // 第2根线 25 CGContextMoveToPoint(ctx, 10, 70); 26 CGContextAddLineToPoint(ctx, 220, 290); 27 28 CGContextStrokePath(ctx); 29 // CGContextDrawPath(ctx, kCGPathStroke); 30 }
运行效果:
2.图形上下文栈机制
画第一条线的时候,会把当前的图形上下文拷贝一份保存到图形上下文栈中。
![](https://images0.cnblogs.com/i/450136/201406/111753059207538.png)
画第二条线的时候,去图形上下文栈中取出栈顶的绘图信息,作为第二条线的状态信息,第二条线的状态信息也是据此(最初保存的那份图形上下文)进行绘制。
![](https://images0.cnblogs.com/i/450136/201406/111754264209678.png)
![](https://images0.cnblogs.com/i/450136/201406/111756201867121.png)
注意:在栈里保存了几次,那么就可以取几次(比如不能保存了1次,取两次,在取第二次的时候,栈里为空会直接挂掉)。