最近在看《iOS 6 Programming Cookbook》的翻译版,它由DevDiv论坛的网友翻译,原文地址:点击跳转。由于下载的pdf都有水印,并且排版不是很好,特别是代码排版,基本不能看,所以这里就整理了一下,方便再次查看。另外把里面提到的点写了一个demo,由于里面一些代码现在已经废弃,所以demo中都是用的新api,下载地址在这里:图形与动画Demo。
1.5 画线
如何使用路径 创建直线。为此,请遵照以下步骤:
- 在你的图形环境选择一个颜色。
- 使用
UIGraphicsGetCurrentContext
函数,获得图形环境的句柄。 - 使用
CGContextMoveToPoint
函数设置线的起点。 - 使用
CGContextAddLineToPoint
函数移动图形环境的画笔,来指定线的终点。 - 使用
CGContextStrokePath
函数创建你的路径。这个过程将使用图形环境当前设置的
颜色来绘制路径。 可选的,你可以使用CGContextSetLineWidth
来设置线的宽度。这个方法的第一个参数是图形环境,第二个参数是线的宽度——浮点型(CGFloat)。
在 iOS 中,线的宽度以逻辑点为单位计量。
下面是一个示例:
- (void)drawRect:(CGRect)rect
{
/* Set the color that we want to use to draw the line */
[[UIColor brownColor] set];
/* Get the current graphics context */
CGContextRef currentContext = UIGraphicsGetCurrentContext(); /* Set the width for the line */
CGContextSetLineWidth(currentContext,5.0f);
/* Start the line at this point */
CGContextMoveToPoint(currentContext,50.0f,10.0f);
/* And end it at this point */
CGContextAddLineToPoint(currentContext, 100.0f,200.0f);
/* Use the context's current color to draw the line */
CGContextStrokePath(currentContext);
}
那么如何接着在(100,100)这个点接着画一条到(300,100)的线呢,在你调用完使用画笔的方法后,它会将画笔留在它 绘制的终点,你只需要用另一个终点,再次调用 CGContextAddLineToPoint
过程,下面是示 例代码:
- (void)drawRect:(CGRect)rect
{
// Drawing code
/* Set the color that we want to use to draw the line */
[[UIColor brownColor] set];
/* Get the current graphics context */
CGContextRef currentContext = UIGraphicsGetCurrentContext(); /* Set the width for the lines */
CGContextSetLineWidth(currentContext, 5.0f);
/* Start the line at this point */
CGContextMoveToPoint(currentContext, 20.0f,20.0f);
/* And end it at this point */
CGContextAddLineToPoint(currentContext,100.0f,100.0f);
/* Extend the line to another point */
CGContextAddLineToPoint(currentContext, 300.0f,100.0f);
/* Use the context's current color to draw the lines */
CGContextStrokePath(currentContext);
}
两条线相遇的点,毫不意外,被称为接合点(join)。使用 Core Graphics
,你可以指定 线和线之间接合点的类型。要设置自己的接合点类型,你必须调用 CGContextSetLineJoin
过 程。它接受两个参数:图形环境和接合点类型,类型必须是 CGLineJoin
类型。CGLineJoin
有以下枚举值:
kCGLineJoinMiter
接合点为尖角。这是默认的接合类型。
kCGLineJoinBevel
接合点为斜角
kCGLineJoinRound
接合点为圆角
效果如下图所示:
为了完成这个,我写了一个名为drawRooftopAtTopPointof:text ToDisplay:lineJoin:
的方 法,它接受三个参数:
- 一个点,屋顶的顶部在这一点
- 屋顶内显示的文字
- 要使用的接合类型
下面是代码:
- (void) drawRooftopAtTopPointof:(CGPoint)paramTopPoint textToDisplay:(NSString *)paramText lineJoin:(CGLineJoin)paramLineJoin{
/* Set the color that we want to use to draw the line */ [[UIColor brownColor] set];
/* Get the current graphics context */
CGContextRef currentContext = UIGraphicsGetCurrentContext(); /* Set the line join */
CGContextSetLineJoin(currentContext,paramLineJoin);
/* Set the width for the lines */
CGContextSetLineWidth(currentContext,20.0f);
/* Start the line at this point */
CGContextMoveToPoint(currentContext,paramTopPoint.x - 140,paramTopPoint.y + 100);
/* And end it at this point */
CGContextAddLineToPoint(currentContext,paramTopPoint.x,paramTopPoint.y);
/* Extend the line to another point to
make the rooftop */
CGContextAddLineToPoint(currentContext,paramTopPoint.x + 140,paramTopPoint.y + 100);
/* Use the context's current color to draw the lines */
CGContextStrokePath(currentContext);
/* Draw the text in the rooftop using a black color */
[[UIColor blackColor] set];
/* Now draw the text */
CGPoint drawingPoint = CGPointMake(paramTopPoint.x - 40.0f, paramTopPoint.y + 60.0f);
[paramText drawAtPoint:drawingPoint
withFont:[UIFont boldSystemFontOfSize:30.0f]];
}
现在,我们在视图对象的 drawRect:
方法中,调用这个方法:
- (void)drawRect:(CGRect)rect{
[self drawRooftopAtTopPointof:CGPointMake(160.0f, 40.0f) textToDisplay:@"Miter"
lineJoin:kCGLineJoinMiter];
[self drawRooftopAtTopPointof:CGPointMake(160.0f, 180.0f) textToDisplay:@"Bevel"
lineJoin:kCGLineJoinBevel];
[self drawRooftopAtTopPointof:CGPointMake(160.0f, 320.0f) textToDisplay:@"Round"
lineJoin:kCGLineJoinRound];
}
1.6 构造路径
路径属于他们被绘制的图形环境。路径没有边界或者指定的形状,而不像在其上绘制的形状那样。不过路径确实有边界矩形(bounding boxes)。请记住,范围(boundaries)不同于边界矩形。范围是一种限制,超出了它你就不能往画布上绘图,而路径的边界矩形是包含已经被画到指定路径上的所有的形状,点和其他对象的最小矩形。你可以把路径看做邮票, 而把图形环境当成信封。每次你给朋友写信的时候,信封可以是相同的,但是你往环境上放 置的东西(邮票或路径)可以不同。
在你完成一条路径的绘制后,你可以将它画到图形环境上。熟悉游戏编程的开发者知道 缓冲(buffers)的概念,他们绘制场景并且在适当的时间,将图像输出(flush)到屏幕。路径 就是这些缓冲。他们就像可以在恰当的时间,被绘制到图形环境上的空画布。
直接操作路径的第一步就是创建他们。创建路径的方法返回一个句柄,你可以在你想往 路径上画点东西的时候使用它,将句柄传给core graphics
可以得到路径的引用。在你创建路 径后,你可以往上面加不同的点,线和形状,然后绘制这条路径。你可以在图形环境上填充 路径,或者用画笔画出它。下面是你要使用的一些方法:
CGPathCreateMutable 函数
创建一个新的 CGMutablePathRef 类型的可变路径并返回其句柄。我们应该在操作完成 后处理它,你后面会看到。
CGPathMoveToPoint 过程
将路径上当前画笔位置移动到 CGPoint 类型的参数指定的点。
CGPathAddLineToPoint 过程
从画笔当前位置向指定位置绘制一条线段。
CGContextAddPath 过程
向图形环境上添加一个路径(由一个路径句柄指定),该路径已经准备好被绘制。
CGContextDrawPath 过程
在图形环境上绘制指定路径
CGPathRelease 过程
释放为路径句柄所分配的内存。
CGPathAddRect 过程
向路径添加一个矩形。这个矩形由 CGRect 结构指定。
你可以要求 CGContextDrawPath 过程执行三种重要的绘制方法:
kCGPathStroke
画线来标记路径的边界或边缘,使用选中的绘图色。
kCGPathFill
用选中的填充色,填充被路径包围的区域。
kCGPathFillStroke
组合绘图和填充。用当前填充色填充路径,并用当前绘图色绘制路径边界。下面我们会看到一个使用此方法的例子。
- (void)drawRect:(CGRect)rect
{
/* Create the path */
CGMutablePathRef path = CGPathCreateMutable();
/* How big is the screen? We want the X to cover
the whole screen */
CGRect screenBounds = [[UIScreen mainScreen] bounds];
/* Start from top-left */
CGPathMoveToPoint(path,
NULL,
screenBounds.origin.x,
screenBounds.origin.y);
/* Draw a line from top-left to bottom-right of the screen */
CGPathAddLineToPoint(path,
NULL,
screenBounds.size.width,
screenBounds.size.height);
/* Start another line from top-right */
CGPathMoveToPoint(path,
NULL,
screenBounds.size.width,
screenBounds.origin.y);
/* Draw a line from top-right to bottom-left */
CGPathAddLineToPoint(path,
NULL,
screenBounds.origin.x,
screenBounds.size.height);
/* Get the context that the path has to be drawn on */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Add the path to the context so we can
draw it later */
CGContextAddPath(currentContext,path);
/* Set the blue color as the stroke color */
[[UIColor blueColor] setStroke];
/* Draw the path with stroke color */
CGContextDrawPath(currentContext,kCGPathStroke);
/* Finally release the path object */
CGPathRelease(path);
}
传给 CGPathMoveToPoint
之类的过程的 NULL
参数,代表了在给定路径上绘制形状和线时可能用到的变换.
1.7 绘制矩形
用 CGPathAddRect
向路径中添加一个矩形,然后在图形环境上绘制这条路径。
- (void)drawRect:(CGRect)rect
{
/* Create the path first. Just the path handle. */
CGMutablePathRef path = CGPathCreateMutable();
/* Here are the rectangle boundaries */
CGRect rectangle = CGRectMake(10.0f, 80.0f, 200.0f, 300.0f);
/* Add the rectangle to the path */
CGPathAddRect(path, NULL, rectangle);
/* Get the handle to the current context */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Add the path to the context */
CGContextAddPath(currentContext,path);
/* Set the fill color to cornflower blue */
[[UIColor colorWithRed:0.20f green:0.60f blue:0.80f alpha:1.0f] setFill];
/* Set the stroke color to brown */
[[UIColor brownColor] setStroke];
/* Set the line width (for the stroke) to 5 */
CGContextSetLineWidth(currentContext, 5.0f);
/* Stroke and fill the path on the context */
CGContextDrawPath(currentContext, kCGPathFillStroke);
/* Dispose of the path */
CGPathRelease(path);
}
这里在路径上画了一个矩形,用矢车菊蓝填充它,并用棕色描出了矩形的边缘。
如果你有多个矩形要绘制,你可以向
CGPathAddRects
过程传递一个 CGrect
对象的数组,如下:
- (void)drawRect:(CGRect)rect
{
/* Create the path first. Just the path handle. */
CGMutablePathRef path = CGPathCreateMutable();
/* Here are the first rectangle boundaries */
CGRect rectangle1 = CGRectMake(10.0f, 10.0f, 200.0f, 300.0f);
/* And the second rectangle */
CGRect rectangle2 = CGRectMake(40.0f, 100.0f, 90.0f, 300.0f);
/* Put both rectangles into an array */
CGRect rectangles[2] = {
rectangle1, rectangle2
};
/* Add the rectangles to the path */
CGPathAddRects(path, NULL, (const CGRect *)&rectangles, 2);
/* Get the handle to the current context */
CGContextRef currentContext = UIGraphicsGetCurrentContext();
/* Add the path to the context */
CGContextAddPath(currentContext,path);
/* Set the fill color to cornflower blue */
[[UIColor colorWithRed:0.20f green:0.60f blue:0.80f alpha:1.0f] setFill];
/* Set the stroke color to black */
[[UIColor blackColor] setStroke];
/* Set the line width (for the stroke) to 5 */
CGContextSetLineWidth(currentContext, 5.0f);
/* Stroke and fill the path on the context */
CGContextDrawPath(currentContext, kCGPathFillStroke);
/* Dispose of the path */
CGPathRelease(path);
}
我们传给 CGPathAddRects
过程的参数有:
- 要添加矩形的路径句柄
- 变换,如果有的话,应用到矩形上。
- CGRect 数组的引用
- 前一个参数中数组的大小。你传入的这个参数一定要和矩形数相等,以避免此过程出 现未知的行为。