1.关于图形上下文栈的操作
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需求,要让右边的那根线不要拥有右边那根线的样式,一切还原(也就是让第二根线不受第一根线设置的状态的影响)
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);
接着执行下面一行代码后内存为下面的状态
//渲染(把当前上下文保存的所有路径都一次性渲染到view上面)
CGContextStrokePath(ctx);
当执行下面几行代码后内存为如下的状态
// 第2根线
CGContextMoveToPoint(ctx,10,70);
CGContextAddLineToPoint(ctx,220,290);
执行下面代码后内存为如下图
//渲染
CGContextStrokePath(ctx);
思路一:
完整代码为
- (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);
这个时候内存状态为:
当执行下面代码后内存为
CGContextMoveToPoint(ctx, 10,70);
CGContextAddLineToPoint(ctx,220,290);
当对第二根线渲染后
CGContextStrokePath(ctx);
思路二:
思路一可以实现但是很麻烦,假设第一根线有很多状态就必须要再写很多状态来覆盖掉才行,所有这就采用图形上下文栈
此时完成代码为:
- (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);
当执行如下代码后内存状态为
// 设置绘图状态
CGContextSetLineWidth(ctx,10);
[[UIColorredColor] set];
CGContextSetLineCap(ctx,kCGLineCapRound);//设置画线的首位为圆状
//第1根线(这个路径暂时添加到上下文对象中)
CGContextMoveToPoint(ctx,50,50);
CGContextAddLineToPoint(ctx,120,190);
当执行下面代码后内存状态为
//渲染(把当前上下文保存的所有路径都一次性渲染到view上面)
CGContextStrokePath(ctx);
执行如下代码后内存状态为下图,也就是把保存在栈顶得上下文出栈替换掉第一根线的上下文)这个时候画第二根线的时候,其上下文状态就完全不受到第二根线的影响
//将栈顶的上下文出栈,替换当前的上下文
CGContextRestoreGState(ctx);