图形与动画(二)--附Demo

最近在看《iOS 6 Programming Cookbook》的翻译版,它由DevDiv论坛的网友翻译,原文地址:点击跳转。由于下载的pdf都有水印,并且排版不是很好,特别是代码排版,基本不能看,所以这里就整理了一下,方便再次查看。另外把里面提到的点写了一个demo,由于里面一些代码现在已经废弃,所以demo中都是用的新api,下载地址在这里:图形与动画Demo

1.5 画线

如何使用路径 创建直线。为此,请遵照以下步骤:

  1. 在你的图形环境选择一个颜色。
  2. 使用 UIGraphicsGetCurrentContext 函数,获得图形环境的句柄。
  3. 使用 CGContextMoveToPoint 函数设置线的起点。
  4. 使用 CGContextAddLineToPoint 函数移动图形环境的画笔,来指定线的终点。
  5. 使用 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
接合点为圆角

效果如下图所示:

图5-1 core Graphics 的三种线的接合类型

为了完成这个,我写了一个名为drawRooftopAtTopPointof:text ToDisplay:lineJoin:的方 法,它接受三个参数:

  1. 一个点,屋顶的顶部在这一点
  2. 屋顶内显示的文字
  3. 要使用的接合类型

下面是代码:

- (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 参数,代表了在给定路径上绘制形状和线时可能用到的变换.

图6-1 使用路径在图形环境上绘图

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);
}

这里在路径上画了一个矩形,用矢车菊蓝填充它,并用棕色描出了矩形的边缘。

图7-1用路径绘制矩形

如果你有多个矩形要绘制,你可以向 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 过程的参数有:

  1. 要添加矩形的路径句柄
  2. 变换,如果有的话,应用到矩形上。
  3. CGRect 数组的引用
  4. 前一个参数中数组的大小。你传入的这个参数一定要和矩形数相等,以避免此过程出 现未知的行为。
图 7-2 一次绘制多个矩形
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容

  • 最近在看《iOS 6 Programming Cookbook》的翻译版,它由DevDiv论坛的网友翻译,原文地址...
    0o冻僵的企鹅o0阅读 876评论 0 0
  • Core Graphics Framework是一套基于C的API框架,使用了Quartz作为绘图引擎。它提供了低...
    ShanJiJi阅读 1,523评论 0 20
  • 最近在看《iOS 6 Programming Cookbook》的翻译版,它由DevDiv论坛的网友翻译,原文地址...
    0o冻僵的企鹅o0阅读 425评论 0 1
  • 一碗浓浓的豆腐鲫鱼汤让冬日里温暖起来,自制肉皮冻健康又美味,还有最爱的大救驾,家乡的味道,完美晚餐,我这个厨子当的...
    nomoi阅读 174评论 0 0
  • 你,有沒有過這樣的時候? 莫名地心情不好,不想和任何人说话,只想一个人静静地发呆,怀念着逝去的人和事。 你,有沒有...
    文文心儿阅读 268评论 2 13