原文:苹果官方文档
本章描述Quartz对文本的基本支持,以及如何在应用程序中使用Quartz2d显示文本。 Quartz 2D 提供了基本的、低级别的绘制文字及符号的接口(使用MacRoman文本编码)。Quartz 2D提供与字体相关的API,可参考CGFont Reference 。
如果你要在iOS上开发一个基于文本的应用程序,首先参考iOS的Text,Web,andEditing编程指南,它描述了iOS对文本的支持。此外,UIKit提供了易于使用的满足一般应用的类:
- UILabel类:绘制1行或多行静态文本,你可以用于标注不同的UI部分。基本的UILabel提供了对显示文本的控制,包括是否有阴影或高亮。如有必要,你可以通过子类化定制文本的显示。
- UITextField 类是为从用户搜集少量文本和一些实时动作而设计的。包括输入搜索文本。
- UITextView类支持特定字体、颜色和对齐方式的文本显示,也支持文本的编辑。尤其用于显示多行文本,比如大文本的显示。
- UIFont类提供了字体选择和设置的接口。
- UIKit扩展了NSString类用于在当前上下文计算和绘制文本。更多信息参考NSString UIKit增强指南。
如果你正在MacOS X上开发基于文本的应用程序,首先请参考Cocoa文本系统,见文档 Cocoa Text Architecture Guide. Cocoa 提供了完全的Unicode 支持,文本输入及编辑, 精确的文本布局及类型设置,字体管理, 以及其他高级文本处理特性。
iOS 3.2 以上及Mac OS X 都支持Core Text, 一种优秀的显示文本和处理字体的底层技术。Core Text 是为高性能设计的,易于使用,允许你在图形上下文中直接绘制unicode字符。如果你正在编写需要精确控制文本显示的应用,请参考Core Text Programming Guide.
如果你仅仅需要使用Quartz 2D提供的最基本的特性在图形上下文中绘制MacRoman字符,请参考本章。
Quartz 2D 如何绘制文本
Quartz 2D 使用字体绘制文本。字体是与字符关联的图形形象的集合。一个字符代表一个抽象意义,如,小写字母B,数字2,“+”号等。你在显示设备上看到的并不是字符本身,而是一个符号,一个路径,是字符的可视化表现。一个符号代表一个字符,例如字母b,多个字符如”fi”;还有不可见字符,如空格。Quartz用ATS框架(Appletype services)提供的字体数据来呈现符号。
字符编码是指将一个字符以某种编码方式映射为一个byte的二进制形式。例如,用ASCII编码用数字65代表大写字母A。当你想打印或显示文本时,你一般是通过字符而不是符号进行的。
你以用户空间坐标来指定文本的位置。文本矩阵规定了由文本空间到用户空间的转换方式。文本位置在文本矩阵的tx和ty变量中存储。当你创建图像上下文时,它以指定的矩阵初始化文本矩阵,文本空间坐标被初始化为用户空间坐标。
Quartz简单地将文本矩阵和当前转换矩阵和其他图形状态参数连接起来,以产生最终的文本渲染矩阵,正是用该矩阵将文本绘制在页上。文本矩阵只存在于文本控件,并不包含字体大小。
Quartz绘制文本时,从ATS中检索对应的符号并用当前图形参数绘制文本,例如填充色(如果文字是实心的)以及描边色。绘制之后,文本位置保留在最后绘制的点处。
控制文本外观
某些图形状态既用于绘制路径也用于文本。如描边色和填充色。(影响文本显示的其他属性和操作请参考“Paths”).
有几种文本绘制属性只应用于文本。用表16-1中的函数设置这些值。注意,CGContextSelectfont函数可以设置字体以及字体大小、文字编码。“绘制文本”讨论了CGContextSelectFone和 CGContextSetFont之间的区别。
Table 16-1文本属性和设置它们的函数 | ||
属性 | 函数 | 说明 |
Font | CGContextSetFont CGContextSelectFont | Typeface. |
Font size | CGContextSetFontSize CGContextSelectFont | 大小(以文本空间单位) |
Character spacing | CGContextSetCharacterSpacing | 字间距(文本空间单位) |
Text drawing mode | CGContextSetTextDrawingMode | 每个符号的绘制方式。参考 Table 16-2 |
Text matrix | CGContextSetTextMatrix | 从文本空间到用户控件的转换矩阵 |
Text position | CGContextSetTextPosition | 文本绘制位置 |
文本矩阵类似当前转换矩阵(CTM),但只用于文本。你可以用任何仿射转换函数对文本矩阵进行复杂的转换。当绘制文本时,quartz使用你指定的文本矩阵。当绘制其他东西时,Quartz使用CTM而不是文本矩阵。
Drawing Text
用Quartz绘制文本需要经过以下步骤:
- 设置字体及字体大小
- 设置绘制模式
- 设置其他——描边色、填充色、背景区域
- 如果需要变换,需要设置文本矩阵、旋转、缩放值
- 绘制
Quartz 2D有两种方法设置字体及大小。CGContextSelectFont或CGContextSetFont+CGContextSetFontSize。CGContextSElectFont更简单一些。CGContextSetFont和CGContectSetFontSize麻烦一些,但你也可能想用Cocoa来设置字体然后进行绘制。因为Quartz在绘制文本上有一些限制。让我们再来比较一下两种方法的区别。
如果对你的应用而言,使用MacRoman文本编码已经足够的话,可以使用CGContextSelectFont函数。在绘制文本时,调用CGContextShowTextAtPoint函数。CGContextSelectFont函数有4个参数:一个图形上下文,字体的PostScript字体名,字体大小(用户空间单位),以及文本的编码。
如果想使用MacRoman以外的文本编码,应该使用CGContextSetFont和CGContextSetFontSize。必须为CGContextSetFont函数提供CGFont类型参数。调用CGFontCreateWithPlatformFont函数可以从ATS字体获得一个CGFont对象。绘制文本时,调用CGContextShowGlyphsAtPoint替代CGContextShowTextAtPoint。
原因就在于,在将文本字节映射为字体符号时,需要指定一个文本编码,默认的文本编码是kCGEncodingFontSpecific,当你调用CGContextShowTextAtPoint时,不能保证一定会获得一个文本编码。由于你调用CGContextSetFont而不是CGContextSelectFont来指定字体,在CGContextSetFont中你并没有指定文本编码,你也就不能使用CGContextShowTextAtPoint来绘制文本。
如果你要用这种方式设置字体,你必须用Cocoa或者自己实现将字符串映射为符号,这样你才能调用CGContextShowGlphsAtPoint。使用Cocoa绘制文本更简单,根本不需要任何Quartz2D函数。现在,你明白了使用Quartz绘制文本的一些限制,我们来看看使用CGContextSelectFont函数的一些例子。CGContextSelectFont函数的使用十分简单,但不建议你在MacRoman以外的编码下使用。清单16-1 显示了MyDrawText函数——用于绘制文本,如图16-1所示。代码后有详细的解释。
Listing16-1Drawing text
void MyDrawText (CGContextRef myContext, CGRect contextRect) // 1 |
{ |
float w, h; |
w = contextRect.size.width; |
h = contextRect.size.height; |
CGAffineTransform myTextTransform; // 2 |
CGContextSelectFont (myContext, // 3 |
"Helvetica-Bold", |
h/10, |
kCGEncodingMacRoman); |
CGContextSetCharacterSpacing (myContext, 10); // 4 |
CGContextSetTextDrawingMode (myContext, kCGTextFillStroke); // 5 |
CGContextSetRGBFillColor (myContext, 0, 1, 0, .5); // 6 |
CGContextSetRGBStrokeColor (myContext, 0, 0, 1, 1); // 7 |
myTextTransform = CGAffineTransformMakeRotation (MyRadians (45)); // 8 |
CGContextSetTextMatrix (myContext, myTextTransform); // 9 |
CGContextShowTextAtPoint (myContext, 40, 0, "Quartz 2D", 9); // 10 |
} |
- 参数:一个图形上下文和一个用于绘制文本的矩形区域。
- 声明仿射渐变矩阵。
- 字体设置为Helvetica,大小为矩形高度/10,使用文本空间单位。在这个例子中,文字是绘制在一个大小可变的窗口中。当用户改变窗口大小,文字大小也随之改变。编码设置为kCGEndodingMacRoman,另外一个选择是kCGEncodingFontSpecific。
- 设置字间距为10个文字空间单位。如果你想增加字间距,请调用这个函数。
- 设置绘制模式:填充+描边。
- 填充色:绿色,alpha值0.5,以呈现部分透明效果。注意,这不是文本特有的属性,填充色会应用到图形状态。
- 设置描边的颜色及透明度。这也不是文本特有属性。
- 创建仿射变换,倾斜45度。MyRadians是一个便利函数,用于将角度转为弧度。你可以自己实现该函数,或者用弧度值替换。否则代码无法编译。
- 用上面创建的变换设置文本矩阵。
- 绘制文本。x,y坐标指定了开始位置(40,0)。此外,还要指定绘制的字符数组,以及字符数组的个数——这里,分别用一个C String字符串和9指定。
对于iOS,必须对当前图像上下文进行转换,以便文字方向与图16-1一样。这个转换可以将y轴的原点置于屏幕底部。清单16-2显示了怎样在drawRect:方法中使用这个转换。然后调用了MyDrawText方法。
Listing 16-2在iOS应用中绘制Quartz 2D文本
- (void)drawRect:(CGRect)rect |
{ |
CGContextRef theContext = UIGraphicsGetCurrentContext(); |
CGRect viewBounds = self.bounds; |
CGContextTranslateCTM(theContext, 0, viewBounds.size.height); |
CGContextScaleCTM(theContext, 1, -1); |
// Draw the text using the MyDrawText function |
MyDrawText(theContext, viewBounds); |
} |
绘制之前计算文本大小
如果文本大小在你的应用中是重要的,可以用Quartz2D计算出来。计算某行文本的尺寸经过以下步骤:
- 调用函数CGContextGetTextPosition获得当前文本位置
- 调用CGContextSetTextDrawingMode函数将文本设置为kCGTextInvisible。
- 调用CGContextShowText绘制文本(在当前位置)。
- 调用CGContextGetTextPosition得到文本的结束位置。
- 用截止位置减去开始位置,即可得到文本的宽度。
复制 Font 变体
字体变体是包含在变体axis中的一个设置,允许你产生一系列打印风格。每个变体axis包括:
- axis名称(如’wght’),指定了该变体axis所包含的风格。在字体变体axis的dictionary中,用关键字kCGFontVariationAxisName来检索。
- 最大值和最小值,在字体变体axis的dictionary中,用kCGFontVariationAxisMinValue和kCGFontVariationAxisMaxValue检索。
- axis的默认值,在dictionary中,由kCGFontVariationAxisDefaultValue指定。
例如,字重axis管理着字重的可能值——最小的值导致该字体以最淡的显示,最大的值产生最粗的字体。默认值使字体正常显示。axis是字体设计者设计的,对于有的字体,字体是可以有变体的,但不是所有字体都有变体。
关于变体,Quartz提供了3个函数:
- CGFontCreateCopyWithVariations,创建一个字体的副本,指定一个变体设置。返回一个针对指定字体应用该变体设置进行变形后的字体。
- CGFontCopyVariations, 返回一个dictionary,包含了该字体所包含的变体,如果该字体不包含变体,返回NULL。
- CGFontCopyVariationAxes, 返回一个数组,包含了该字体所包含的变体axis的dictioanrys,如果字体不支持变体,返回NULL。
Quartz 提供如下函数以支持PostScript字体:
- 获取PS字体名
- 判断是否可用PS格式创建一个字体的子集
- 创建字体的PS子集
- 创建字体的PS编码
如果你想使用PS字体,请参考CGFont Reference .