当iOS系统自动调用drawRect:方法时,iOS系统会创建并配置好一个图形的上下文环境,如同理解一篇文章中某个句子的意思需要了解这个句子的上下文环境一样,图形上下文环境即等同于这篇文章。
在动笔绘图前,iOS 系统已经完成了所有的初始化和配置工作,可以通过UIGraphicsGetCurrentContext()方法来获得图形上下文环境,这个方法返回一个CGContextRef对象:
CGContextRef context = UIGraphicsGetCurrentContext ();
更多信息:UIGraphicsGetCurrentContext()实际上是C语言函数,我们使用核心绘图C函数,而不是Objective-C对象来绘图,本章中的图形代码大多由C函数调用组成。
接下来,我们将介绍如何通过不同的C函数组合来绘制不同形状的图形。
1.绘制线条
可以在drawRect:方法中通过如下的代码来绘制线条:
CGContextRef context = UIGraphicsGetCurrentContext (); //获得图形上下文环境 CGContextSetLineWidth(context, 2.0); //设置线条的宽度 CGContextMoveToPoint(context, 10.0, 20.0); //设置线条的起点在坐标图中的位置 CGContextAddLineToPoint(context, 310.0, 30.0); //设置线条的终点在坐标图中的位置 CGContextSetStrokeColorWithColor(context, [UIColor purpleColor].CGColor); //设置线条的颜色为紫色 CGContextStrokePath(context); //画线
上述代码将在屏幕上坐标(10.0,20.0)到坐标(310.0,30.0)之间画一条宽度为 2.0的紫色线条,真正画线的那行代码是CGContextStrokePath(context)。
CGContextSetStrokeColorWithColor方法是C语言方法,不能直接处理Objective-C对象,因此通过UIColor的CGColor属性返回相应颜色的CGColor结构体供该方法调用。
2.绘制矩形
绘制矩形与绘制直线非常类似,从数学角度来说,一旦直线的长度和位置定了,矩形的位置也就定了,通过Quartz绘制图形则通过CGRect结构体来描述矩形的位置和大小。
可以通过CGContextAddRect方法告诉图形上下文环境矩形的位置信息,示例代码如下:
CGContextAddRect(context, CGRectMake(50.0f, 50.0f, 100.0f, 120.0f));
此外,与直线不同的是绘制矩形除了指定矩形四边线条的颜色外,矩形内部区域的填充颜色也需要定义,为此可以通过CGContextSetFillColorWithColor方法来指定填充颜色。最后矩形的绘制方法也可以使用和直线同样的方法CGContextStrokePath,但该方法只支持绘制矩形的四边,不支持矩形内部填充颜色的绘制,即使指定了内部填充颜色,通过该方法绘制出来的矩形中间区域将与父视图背景色相同。
如果需要能绘制内部填充色,需要使用方法CGContextDrawPath。该方法接受两个参数,第一个参数是图形上下文环境,第二个参数是枚举变量 CGPathDrawingMode 类型参数。第二个参数指定了绘制矩形的模式,该枚举类型定义如下:
enum CGPathDrawingMode { kCGPathFill, kCGPathEOFill; kCGPathStroke, kCGPathFillStroke, kCGPathEOFillStroke } typedef enum CGPathDrawingMode CGPathDrawingMode;
需要说明的是这些枚举变量不仅对矩形有效,针对其他的封闭图形绘制,比如后面要介绍到圆形、多边形等也是一样的。下表是对其中每个枚举变量的说明。
方法 | 描述 |
kCGPathFill | 仅填充形状内部颜色 |
kCGPathEOFill | 按照一种称为“奇偶规则” 的矢量图算法对内部颜色进行填充 |
kCGPathStroke | 仅绘制形状边缘线条,不绘制内部填充颜色 |
kCGPathFillStroke | 既绘制形状边缘线条,也绘制内部填充颜色 |
kCGPathEOFillStroke | 既绘制形状边缘线条,也按照一种称为“奇偶规则” 的矢量图算法填充形状内部颜色 |
基于这些知识可以通过下面的代码来绘制矩形:
CGContextRef context = UIGraphicsGetCurrentContext (); CGContextSetLineWidth (context, 3.0); CGContextSetStrokeColorWithColor (context, [UIColor purpleColor].CGColor); CGContextSetFillColorWithColor (context, [UIColor colorWithRed: 0.5f green: 0.5f blue: 0.5f alpha: 0.8f].CGColor); //矩形内部填充颜色 CGContextAddRect (context, CGRectMake (50.0f, 50.0f, 200.0f, 100.0f)); //矩形的左上角顶点及长方形的宽和高 CGContextDrawPath (context, KCGPathFillStroke); //画图,既要绘制矩形四边线条,也要填充矩形内部颜色
上面的代码将在视图中点(50.0,50.0)开始画一个宽200.0,高100.0的矩形,其中矩形边宽3.0,线条颜色为紫色,矩形内部填充颜色为自定义颜色。
3.绘制圆形和弧线
通过 Quartz 绘制圆形和绘制椭圆在 Objective-C中是同一个方法——CGContext FillEllipseInRect(CGContextRef context,CGRect rect)。
该方法顾名思义就是在矩形内部画出一个椭圆,这和椭圆在数学上的定义也是吻合的,沿着矩形的内部绘制一个与四条边相切的形状就是椭圆。如果矩形的四边相等就是正方形,在正方形内部绘制的椭圆就是圆了。
该方法接受的第二个参数CGRect指定的正是包含椭圆的矩形的位置和大小信息。这样,描绘椭圆的代码和描绘矩形的代码就非常类似了。下面的代码将描绘一个纵轴长100、横轴长200的椭圆,与前面描绘矩形的代码相比,仅第5行不同,使用了不同的方法来绘制:
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 3.0); CGContextSetStrokeColorWithColor(context, [UIColor purpleColor].CGColor); CGContextSetFillColorWithColor(context, [UIColor colorWithRed: 0.5f green: 0.5f blue: 0.5f alpha: 0.8f].CGColor); CGContextFillEllipseInRect(context, CGRectMake(50.0f, 50.0f, 200.0f, 100.0f)); CGContextDrawPath(context, KCGPathFillStroke);
最后一步第6行绘制椭圆形的代码同样可以替换成CGContextStrokePath(context),该方法将仅绘制椭圆的边线,而不填充椭圆内部颜色。
绘制弧线代码的思路和用圆规在视图上画圆弧非常类似,首先需要知道圆点在哪里、半径是多少、弧线的起点和终点又分别在哪里,这些因素一旦确定,弧的位置和形状也就确定了。而方法CGContextAddArc正包含了这些所有的要素,该方法的定义如下:
CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise);
方法的第一个参数指定了图形上下文环境,第二个和第三个参数指定了圆心在视图坐标系中的位置,第四个和第五个参数指定了弧线的起点和终点,单位是弧度(完整的圆的弧度是 2π),第六个参数指定的是画弧的方向,如果是 1,则从起点到节点逆时针画弧,如果是0,则顺时针画弧。下面的代码将以(150.0,150.0)为圆心,30.0位半径,从弧度π开始到3π/2逆时针画弧:
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 3.0); CGContextSetStrokeColorWithColor(context, [UIColor purpleColor].CGColor); CGContextSetFillColorWithColor(context, [UIColor colorWithRed: 0.5f green: 0.5f blue: 0.5f alpha: 0.8f].CGColor); CGContextAddArc(context, 150.0f, 150.0f, 30.0f, M_PI, 3*M_PI/2, 1); CGContextDrawPath(context, KCGPathFillStroke);
其中M_PI是iOS系统预置定义的宏,定义如下:
#define M_PI 3.14159265358979323846264338327950288 /* pi */
4.绘制多边形
绘制多边形与绘制直线的思路一样,首先找到第一个点,然后不断地通过CGContextAddLineToPoint来画线条,最后通过CGContextClosePath方法来关闭形状。下面的代码将绘制一个五角星,其中sinf和cosf是系统预置定义的数学函数:
CGContextRef context = UIGraphicsGetCurrentContext (); CGContextSetStrokeColorWithColor (context, [UIColor blueColor].CGColor); CGContextSetFillColorWithColor (context, [UIColor redColor].CGColor); CGContextSetLineWidth (context, 2.0); CGPoint center; center = CGPointMake (90.0, 90.0); CGContextMoveToPoint (context, center.x, center.y + 60.0); for(int i = 1; i< 5; i++) { CGFloat x = 60.0 * sinf (i * 4.0 * M_PI / 5.0); CGFloat y = 60.0 * cosf (i * 4.0 * M_PI / 5.0); } CGContextClosePath(context); CGContextDrawPath(context, KCGPathFillStroke);
关于绘图的知识点还不止这些,比如如何绘制PDF文件、如何将图片文件绘制出来等等,由于篇幅所限,本节不能一一展开,需要时可以通过查阅苹果公司开发者中心网站来获取更多帮助信息。