CGContextRef为绘制文字提供了如下函数。
CGAffineTransform CGContextGetTextMatrix(CGContextRef c):获取当前对文本执行变换的变换矩阵。
CGPoint CGContextGetTextPosition(CGContextRef c):获取该CGContextRef中当前绘制文本的位置。
CGContextSelectFont(CGContextRef c, const char *name, CGFloat size, CGTextEncoding textEncoding):设置该CGContextRef当前绘制文本的字体、字体大小。
void CGContextSetCharacterSpacing(CGContextRef c, CGFloat spacing):设置该CGContextRef中绘制文本的字符间距。
void CGContextSetFont(CGContextRef c, CGFontRef font):设置该CGContextRef中绘制文本的字体。
void CGContextSetFontSize(CGContextRef c, CGFloat size):设置该CGContextRef中绘制文本的字体大小。
CGContextSetTextDrawingMode(CGContextRef c, CGTextDrawingMode mode):设置该CGContextRef绘制文本的绘制模式。该函数支持kCGTextFill、kCGTextStroke、kCGTextFillStroke等绘制模式。
void CGContextSetTextMatrix(CGContextRef c, CGAffineTransform t):设置对将要绘制的文本执行指定的变换。
CGContextSetTextPosition(CGContextRef c , CGFloat x, CGFloat y):设置CGContextRef的一个文本的绘制位置。
void CGContextShowText(CGContextRef c,
const char *string,
size_t length):控制CGContextRef在当前绘制点绘制指定文本。
void CGContextShowTextAtPoint (CGContextRef c,
CGFloat x,
CGFloat y,
const char *string,
size_t length):控制CGContextRef在指定绘制点绘制指定文本。
除此之外,系统还为NSString提供了一个UIStringDrawing分类,通过该分类为NSString增加了drawAtPoint:withAttributes:、drawInRect:withAttributes:等绘制方法,通过这些绘制方法可以更方便地绘制字符串。
总结起来,使用CGContextRef绘制文本的步骤如下。
获取绘图的CGContextRef。
设置绘制文本的相关属性,例如,绘制文本所用的绘制方式、字体大小、字体名称等。
如果只是绘制不需要进行变换的文本,直接调用NSString的drawAtPoint:withAttributes:、drawInAttributes:withFont:等方法绘制即可。如果需要对绘制的文本进行变换,则需要先调用CGContextSetTextMatrix()函数设置变换矩阵,再调用CGContextShowTextAtPoint()方法绘制文本。
下面的程序示范了如何利用Quartz 2D绘制文本。首先创建一个Single View Application,该Application包含一个应用程序委托代理类、一个视图控制器和配套的Storyboard界面设计文件。将该界面设计文件中最大的View改为使用自定义的FKTextView类,并向该界面设计文件添加两个UISlider控件。为了让这两个UISlider控件控制文本的缩放和旋转角度,将控制缩放的UISlider的最小值、最大值分别设置为0.1、5;将控制旋转的UISlikder的最小值、最大值设分别为-90、90,程序为两个UISlider的Value Changed事件分别绑定scaleChanged:和rotateChanged: IBActino方法。
下面是该应用的视图控制器类的实现代码。
程序清单:codes/12/12.2/DrawTextTest/DrawTextTest/FKViewController.m
- @implementation FKViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- self.view.backgroundColor = [UIColor whiteColor];
- }
- - (IBAction)scaleChanged:(id)sender
- {
- // 修改FKTextView的scaleRate属性
- ((FKTextView*)self.view).scaleRate = ((UISlider*)sender).value;
- }
- - (IBAction)rotateChanged:(id)sender
- {
- // 修改FKTextView的rotateAngle属性
- ((FKTextView*)self.view).rotateAngle = ((UISlider*)sender).value;
- }
- @end
从上面的控制器代码可以看出,当用户拖动界面的UISlider时,视图控制器中的监听器方法就会改变FKTextView控件的scaleRate、rotateAngle属性。当这些属性被修改时,FKTextView就会使用特定的缩放比、旋转角重绘文本。下面是FKTextView类的实现代码。
程序清单:codes/12/12.2/DrawTextTest/DrawTextTest/FKTextView.m
- @implementation FKTextView
- - (void)setScaleRate:(CGFloat)scaleRate
- {
- if(_scaleRate != scaleRate)
- {
- _scaleRate = scaleRate;
- [self setNeedsDisplay]; // 通知该控件重绘自己
- }
- }
- - (void)setRotateAngle:(CGFloat)rotateAngle
- {
- if(_rotateAngle != rotateAngle)
- {
- _rotateAngle = rotateAngle;
- [self setNeedsDisplay]; // 通知该控件重绘自己
- }
- }
- // 重写该方法绘制该控件
- - (void)drawRect:(CGRect)rect
- {
- CGContextRef ctx = UIGraphicsGetCurrentContext(); // 获取该控件的绘图CGContextRef
- CGContextSetCharacterSpacing (ctx, 4); // 设置字符间距
- CGContextSetRGBFillColor (ctx, 1, 0, 1, 1); // 设置填充颜色
- CGContextSetRGBStrokeColor (ctx, 0, 0, 1, 1); // 设置线条颜色
- CGContextSetTextDrawingMode (ctx, kCGTextFill); // 设置使用填充模式绘制文字
- // 绘制文字
- [@"疯狂iOS讲义" drawAtPoint:CGPointMake(10 ,20)
- withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
- [UIFont fontWithName:@"Arial Rounded MT Bold" size: 45],
- NSFontAttributeName,
- [UIColor magentaColor] , NSForegroundColorAttributeName , nil]];
- // 设置使用描边模式绘制文字
- CGContextSetTextDrawingMode (ctx, kCGTextStroke);
- // 绘制文字
- [@"疯狂Android讲义" drawAtPoint:CGPointMake(10 ,80)
- withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
- [UIFont fontWithName:@"Heiti SC" size: 40],NSFontAttributeName,
- [UIColor blueColor] , NSForegroundColorAttributeName , nil]];
- // 设置使用填充、描边模式绘制文字
- CGContextSetTextDrawingMode (ctx, kCGTextFillStroke);
- // 绘制文字
- [@"疯狂Ajax讲义" drawAtPoint:CGPointMake(10 ,130)
- withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
- [UIFont fontWithName:@"Heiti SC" size: 50], NSFontAttributeName,
- [UIColor magentaColor] , NSForegroundColorAttributeName , nil]];
- // 定义一个垂直镜像的变换矩阵
- CGAffineTransform yRevert = CGAffineTransformMake(1, 0, 0, -1, 0, 0);
- // 设置绘制文本的字体和字体大小
- CGContextSelectFont (ctx, "Courier New" , 40, kCGEncodingMacRoman);
- // 为yRevert变换矩阵根据scaleRate添加缩放变换矩阵
- CGAffineTransform scale = CGAffineTransformScale(yRevert,
- self.scaleRate, self. scaleRate);
- // 为scale变换矩阵根据rotateAngle添加旋转变换矩阵
- CGAffineTransform rotate = CGAffineTransformRotate(scale,
- M_PI * self.rotateAngle / 180);
- CGContextSetTextMatrix(ctx, rotate); // 对CGContextRef绘制文字时应用变换
- CGContextShowTextAtPoint(ctx, 50, 300, "crazyit.org", 11); // 绘制文本
- }
- @end
上面的程序中,前三行粗体字代码直接调用了NSString的drawAtPoint:withAttributes:方法进行绘制--这是一种非常简单的绘制方式。
接下来需要对绘制的文本执行坐标变换,因此程序中先用CGAffineTransformMake()函数定义了一个变换矩阵:(1, 0, 0, -1, 0, 0),该变换矩阵将会对绘制的文本做垂直镜像。此处这么做的原因是因为Quartz 2D本身的坐标系统与UIView控件绘图的坐标系统并不相同,Quartz 2D为了照顾开发者的习惯,已经对坐标系统做过变换,但它在处理文本变换时少了一次垂直镜像变换,导致绘制出来的文本总是上下颠倒的。为了解决这个问题,笔者先对文本做了一次垂直镜像变换。
关于坐标变换的详细理论,后面会详细阐述,读者可参考相关内容。
然后利用CGAffineTransformScale()、CGAffineTransformRotate()增加了缩放、旋转变换,程序最后一行粗体字代码调用CGContextShowTextAtPoint()方法绘制了文本,该文本将会带有缩放和旋转效果。
上面的程序中,在绘制文本时,使用了大量iOS支持的字体,如果读者需要获取iOS支持的所有字体,可调用UIFont类的familyNames类方法,该方法返回一个数组,该数组包含iOS所支持的全部字体。
编译、运行该程序,用户即可通过拖动界面上的UISlider控件来改变文本的缩放、旋转,效果如图12.5所示。