在iOS上无论采用哪种绘图技术(UIKit、Quartz 2D、Core Animation和OpenGL ES),都离不开UIView,绘制都发生在UIView对象的区域内。在绘制发生的时候如果使用的是系统提供的视图,绘制工作会自动得到处理。然而,如果是自定义视图,则必须重写drawRect:方法,在此提供相应的绘制代码。
在iOS上绘制的时候比较麻烦,不会简单地调用一个方法就可以绘制出来了。而是首先为需要绘制的视图或视图的部分区域设置一个需要绘制的标志,在事件循环的每一轮中,绘图引擎会检查是否有需要更新的内容,如果有就会调用视图的drawRect:方法进行绘制,因此我们需要绘制的视图中重写drawRect:方法。
一旦drawRect:方法被调用,就可以使用任何的UIKit、Quartz 2D、OpenGL ES等技术对视图的内容进行绘制了。
绘图过程中除了使用drawRect:方法,还有setNeedsDisplay和setNeedsDisplayInRect:。setNeedsDisplay和setNeedsDisplayInRect:方法是设置视图或者视图部分区域是否需要重写绘制,setNeedsDisplay是重新绘制整个视图,setNeedsDisplayInRect是重新绘制视图的部分区域。原则上,尽量不要绘制视图的全部,以减少绘制带来开销。触发视图重新绘制的动作有如下几种:
图2-1 绘制实例:填充矩形
下面通过一个简单实例了解一下视图绘制的过程。如图2-1所示,我们在整个视图中填充为褐色。
实现过程的具体步骤如下:首先来创建一个FillingRect工程,本书采用Xcode5工具,启动Xcode,选择File→New→Project菜单,在打开的Choose a template for your new project界面中,选择Single View Application工程模板(如图2-2所示)。
图2-2 选择工程模板
然后单击Next按钮,随即出现图2-3所示的界面。
图2-3 新工程中的选项
在Product Name中输入FillingRect作为工程名,其他项目采用默认值就可以了。设置完相关的工程选项后,单击Next按钮,选择保存工程目录后创建工程。
创建完成工程后,我们需要添加一个自定义的视图类,选择菜单中的New File…弹出选择创建文件模板对话框,选择iOS→Cocoa Touch→Objective-C class,出现如图2-4所示的对话框,在Class中输入FillingView,在Subclass of 中选择UIView。然后单击Next按钮FillingView。
图2-4 创建视图类
创建完成之后FillingView.h文件代码如下所示。
#import <UIKit/UIKit.h> @interface FillingView: UIView @end
FillingView.m文件代码如下所示。
#import "FillingView.h" @implementation FillingView -(id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code } return self; } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. -(void)drawRect:(CGRect)rect { // Drawing code } */ @end
其中,drawRect:方法是被注释掉的,需要重写这个方法,在这里编写视图填充代码,修改该方法内容如下所示。
-(void)drawRect:(CGRect)rect { [[UIColor brownColor] setFill]; UIRectFill(rect); }
这两条语句都属于UIKit提供的,其中[[UIColor brownColor]setFill]语句是为当前的图形上下文设置要填充的颜色。函数UIRectFill(rect)是按照刚才设置的颜色进行填充矩形。
代码部分就这么多,应用要想运行还需要将根视图控制器中的默认视图(UIView)修改成为自定义的视图(FillingView)。打开主故事板文件Main.storyboard,选择View对象,打开标识检查器
,如图2-5所示,在Custom Class中选择Class为FillingView。
图2-5 选择自定义视图
设计完成最后,就可以运行一下看看效果,从整个设计过程看,主要工作是在重写drawRect:方法。
UIKit提供非常基本的绘图功能,主要的API有:
UIKit虽然提供了UIBezierPath等类,但是对于线段、渐变、阴影、反锯齿等高级特性支持还是不及Quartz 2D。
下面来看看UIRectFrame(CGRect rect)函数的使用,修改FillingView视图的drawRect:方法如下所示。
-(void)drawRect:(CGRect)rect { [[UIColor brownColor] setFill]; UIRectFill(rect); [[UIColor whiteColor] setStroke]; ① CGRect frame = CGRectMake(20, 30, 100, 300); UIRectFrame(frame); ② }
图2-6 矩形描边
代码第①~②行是在视图上绘制一个红色的矩形边框,绘制边框过程称为“描边”(Stroke),其中[[UIColor whiteColor] setStroke]是设置图形上下文红色描边,如图2-6所示。
除了可以绘制几何图形外,也可以绘制文本和图像。这就像是使用Interface Builder工具从对象库中拖拽出来的标准控件(UILabel和UIImageView)一样。这些绘制可以使用UIImage和NSString实现。它们对应的绘制方法如下。
UIImage类中绘制图像主要的方法:
NSString类中绘制文本主要的方法:
下面通过一个实例介绍图像和文本的绘制,实例界面如图2-7中所示,界面中看到的图片和文字都不是使用标准控件设计出来的,而是通过绘制方法绘制出来的。
![]() |
![]() |
![]() |
图2-7 绘制方法
参考2.1.2构建工程ImageString,自定义视图类MyView.m代码如下所示。
#import "MyView.h" @implementation MyView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code } return self; } - (void)drawRect:(CGRect)rect { NSString* imagePath = [[NSBundle mainBundle] pathForResource: @"dog" ofType:@"png"]; ① UIImage* myImageObj = [[UIImage alloc] initWithContentsOfFile:imagePath]; [myImageObj drawInRect:CGRectMake(0, 40, 320, 400)]; NSString *s = @"我的小狗"; UIFont *font = [UIFont systemFontOfSize:34]; ② NSDictionary *attr = @{NSFontAttributeName:font}; ③ [s drawAtPoint:CGPointMake(100, 20) withAttributes:attr]; ④ } @end
本例中第①行代码使用[myImageObj drawInRect:CGRectMake(0,0,320,400)]语句把图片放在矩形中显示,由于矩形高宽比例与图片的原始比例不一样导致图片变形,这是使用drawInRect:方法进行绘制图片时需要注意的。
代码第②~③行设置一个字体属性,第④行代码是绘制字符串。一般而言,不需要使用这种方式绘制字符串,而是使用UILabel控件。