在前面的实例中多次提到图形上下文,这是一个什么概念呢?举例来说,在周末的时候我经常陪着我女儿去画画,当想画灰太狼时她会拿起一只灰色的蜡笔,当画红太狼时她还要另外一只红色的蜡笔。我们要介绍的图形上下文就是相当于她的手。当切换图形上下文的颜色及其他参数时,就是在替换不同的蜡笔。前面的实例里[UIColor brownColor],就是拿起蓝色的蜡笔。我们还可以给图形上下文设置很多变量赋值,从而改变绘制的样式。
图形上下文包含绘制系统执行后,绘制命令所需要的信息,定义了各种基本的绘制参数,比如绘制使用的颜色、裁剪区域、线段的宽度及风格信息、字体信息、合成选项以及几个其他信息。
在调用drawRect:方法之前,视图对象会自动配置其绘制环境,使代码立即执行进行绘制。作为这些配置的一部分,UIView对象会为当前绘制环境创建一个图形上下文(对应于CGContextRef封装类型)。在前面的实例中就是采用这种默认方式的图形上下文。
我们也可以在drawRect:方法中通过(CGContextRef)UIGraphicsGetCurrentContext(void)函数获得访问图形上下文对象。图形上下文仅对当前的drawRect:方法调用有效,不要把图形上下文对象设置为成员变量。
图2-8 绘制实例:描边和填充三角形
让我们通过一个简单实例了解一下视图绘制的过程。实例如图2-8所示,我们在整个视图中绘制一个红色三角形。
首先来创建一个StrokedFilledTriangle工程,并创建自定义视图类DrawView。然后打开主故事板,选择View对象,打开标识检查器,在Custom Class中选择Class为DrawView。具体步骤请参考2.1.2节。
然后修改DrawView.m文件代码如下所示。
#import "DrawView.h" @implementation DrawView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code } return self; } - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); ① CGContextMoveToPoint(context, 75, 10); ② CGContextAddLineToPoint(context, 10, 150); CGContextAddLineToPoint(context, 160, 150); CGContextClosePath(context); ③ // 设置黑色描边参数 [[UIColor blackColor] setStroke]; // 设置红色条填充参数 [[UIColor redColor] setFill]; //绘制路径 CGContextDrawPath(context, kCGPathFillStroke); ④ } @end
在drawRect:方法中第①~④行是获得图形上下文和设置参数。其中CGContextRef context = UIGraphicsGetCurrentContext()是创建图形上下文对象。其中第②~③语句是与路径有关,关于路径问题我们将在2.3节介绍。
有的时候需要多次改变图形上下文对象的参数,这样两次绘制就可能互相有影响,这就好像拿着蜡笔画画,每一次我的手只能拿一支蜡笔。为了防止互相影响,需要CGContextSaveGState函数保存图形上下文设置,绘制完成我们再使用CGContextRestoreGState函数恢复图形上下文设置。下面的代码运行的结果是什么呢?
- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextMoveToPoint(context, 75, 10); CGContextAddLineToPoint(context, 10, 150); CGContextAddLineToPoint(context, 160, 150); CGContextClosePath(context); [[UIColor blackColor] setStroke]; ① [[UIColor greenColor] setFill]; ② CGContextSaveGState(context); ③ [[UIColor redColor] setFill]; ④ CGContextRestoreGState(context); ⑤ CGContextDrawPath(context, kCGPathFillStroke); }
在上面的代码的第①~②行设置的图形上下文参数是黑色描边,绿色填充。而在第④行设置了上下文参数是红色填充,这就与第②行产生了冲突,我们在第③行CGContextSaveGState函数保存上下文参数,在第⑤行使用CGContextRestoreGState函数恢复之前的上下文参数。因此最后绘制出来的三角形填充的颜色为绿色。