CodeV

1.10-上下文状态

在清单 1-8 中,set方法在颜色实例上调用时,指定了当前上下文中后续fill和stroke操作的颜色。在该列表中,首先设置紫色,然后设置绿色。 指定每种颜色后,它将应用于所有的后续绘制操作。

两种相关的方法指定了颜色是只用于fill(setFill)还是只用于stroke(setStroke)操作。fill用于使形状的内部完全着色。stroke用来描绘该形状边框。在图1-9中,填充颜色为绿色,描边颜色为紫色。

所有的这三个方法(setsetFillsetStroke)更新当前绘制状态,指定活动的填充和描边颜色。

图1-9

图 1-9 上下文描边和填充颜色适用于所有后续绘图操作。

应用状态

下面的代码,用于创建如图 1-9 所示的图形:

1
2
3
4
[greenColor setFill];
[purpleColor setStroke];
[bunnyPath fill];
[bunnyPath stroke];

它们设置填充颜色和描边颜色,然后应用到贝塞尔曲线路径。最大的问题是:谁是这些调用的目标?谁存储填充颜色和描边颜色的状态,允许它们应用到以后的绘图操作中?

答案是当前的上下文。UIGraphicsGetCurrentContext()返回的对象存储填充颜色和描边的颜色。每个设置和绘图方法会自动推断出该上下文。

所有上下文存储用作绘图操作参数的图形状态信息。填充颜色和描边颜色只是保存到上下文的两种类型的状态。你会发现,上下文可以存储相当多的信息。 图形状态是通过调整每个操作的实现的方式来影响绘制操作。

图形状态的压栈与出栈

每个上下文都拥有多个图形状态的设置。每次创建一个新的上下文时,栈以一个新的状态开始。您可以修改该状态,并且如果有需要,也可以从图形状态(GState)堆栈将该状态的副本压入和弹出。

此栈与UIKit维护的上下文栈不同。该栈存储绘制目的地,让您通过压栈和出栈的方式在上下文之间切换。绘图目的地就像画布,当您更改上下文栈时,就相当于要选择绘制在哪个画布上。状态栈是特定于每个上下文的,它拥有一套适用于这个上下文的绘图偏好设置,以及改变绘图操作对每个“画布”的应用方式。两者都使用栈管理,但它们影响图形系统的不同部分。

每个图形状态保存了对它所做的任何更改。例如,如果将一个新状态压入栈中并将默认线宽调整为10,那么上下文状态将一直保持这种,直到它从栈弹出,之后,默认线宽返回到创建该状态之前的值。

代码清单 1-9 演示了管理图形状态栈的过程。它将填充颜色和描边颜色设置为图 1-9 中使用的相同的绿色和紫色。绘制一个兔子,然后通过调用CGContextSaveGState()“保存”当前状态,将状态的副本压入到上下文的GState堆栈,现在对上下文的任何更改都将应用于图形状态的新副本。

如果你继续绘制而没有对该状态做任何更改,你将继续创建带有紫色轮廓的绿色兔子。但是,清单 1-9 在绘制之前更新了其颜色,这些新颜色是橙色和蓝色,并且它们覆盖掉了当前状态的任何先前的颜色设置。当绘制第二个兔子时,它显示为橙色和蓝色。

最后,列表通过调用CGContextRestoreGState()来恢复先前的图形状态。这将弹出堆栈,丢弃对新的状态副本的任何更改。最后绘制的兔子因此回到原来的颜色状态,即紫色和绿色。图 1-10 显示了清单 1-9 中详细描述的绘图操作的结果。

清单 1-9 管理状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
// Set initial stroke/fill colors

[greenColor setFill];
[purpleColor setStroke];

// Draw the bunny
[bunnyPath fill];
[bunnyPath stroke];

// Save the state
CGContextSaveGState(context);

// Change the fill/stroke colors
[[UIColor orangeColor] setFill];
[[UIColor blueColor] setStroke];

// Move then draw again
[bunnyPath applyTransform:CGAffineTransformMakeTranslation(50, 0)];
[bunnyPath fill];
[bunnyPath stroke];

// Restore the previous state
CGContextRestoreGState(context);

// Move then draw again
[bunnyPath applyTransform:CGAffineTransformMakeTranslation(50, 0)];
[bunnyPath fill];
[bunnyPath stroke];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

图1-10

图 1-10 用于绘制第二个兔子的颜色变化在将图形状态恢复到之前的设置时被丢弃。

状态类型

上下文保存多种状态,而不仅仅是填充和描边设置。这些状态中的每一个状态都表示当前上下文的持续性。表 1-1 列出了可以使用Core Graphics上下文调用进行调整的可自定义状态属性,并提供了一些可视化的示例,以粗略地演示可以对这些设置进行的更改类型。

表格 1-1 上下文状态

技术 说明
表格1-1图1 颜色 - 颜色状态由指定项目如何绘制到上下文的填充颜色和描边颜色设置组成。
表格1-1图2 矩阵变换 - 它将几何变换应用于上下文,允许您旋转,缩放和平移您正在绘制的画布,以创建复杂的几何结果。
表格1-1图3 裁剪 - 裁剪上下文时,您将创建一个自动排除(形状外)内容的形状。这使您可以在圆形,矩形或您可以想象的任何其他形状的范围内构建内容。
表格1-1图4 线参数 - 线状态描述了Quartz如何绘制线条。这些状态包括线宽(线的粗细),虚实线的模式(用于绘制线的模式),斜接限制(尖角瑞丽程度如何),连接样式(相交角如何表示;样式包括miter,round或bevel) ,和caps(线的末端,绘制为对接(butt),圆形(round)和正方形(square))。
表格1-1图5 平坦度 - 这是一个决定每个弯曲路径段的精确度的因素,指定数学曲线上的点与渲染点之间的最大允许距离。默认值为0.6。较大的值则产生更多锯齿曲线,但是它们渲染得更快,因为它们需要更少的计算。
表格1-1图6 抗锯齿 - 这决定了Quartz可通过平均像素之间的值这种数学方法来使曲线和对角线上的锯齿线更加平滑。 抗锯齿比正常绘制慢,但其结果在视觉上更优越。Quartz默认使用抗锯齿。
表格1-1图7 alpha值 - 它们控制绘制到上下文的材质的透明度。当alpha值从1(完全不透明)降低到0(完全不可见)时,绘制的材料变得越来越透明。
表格1-1图8 文本特征 - 文本状态包括字体,字体大小,字符间距和文本绘制模式。模式指定如何绘制文本(通过描边,填充等)。其他细节控制字体平滑和子像素定位。
表格1-1图9 混合模式 - 混合模式使用颜色和alpha值来确定如何将每个新的颜色层混合到目标中已有的材质中。 Quartz提供了多种混合模式。附录A详尽地探讨了这些模式。

本文翻译自《iOS Drawing Practical UIKit Solutions》作者:Erica Sadun,翻译:Cheng Dong。如果觉得本书不错请购买支持正版:亚马逊购买传送门,本书所有源代码可在GitHub上下载。译者虽然力求做到信,达,雅,但是由于时间仓促加之译者水平十分有限,文中难免会出现不正确,不准确,词不达意,难于理解的地方,还望各位批评指正,共同进步,谢谢。转载请注明出处。