Quartz 2D 绘图技术

Quartz 2D。是 iOS 和 Mac OS X 环境下的2D绘图引擎。Quartz 2D 也被称为 Core Graphics,缩写前缀为CG,Quartz 2D 与 Quartz Compositor 统称为 Quartz,Quartz 原本是 Mac OS X 的 Darwin 核心之上的绘图技术。它的 API 接口都是基于 C 的。


1.绘制原理

摆事实,讲道理。在 iOS 中,所有的绘制都离不开 UIView ,绘制都发生在 UIView 对象区域内。在绘制发生的时候,如果是使用的系统提供的视图,则绘制工作会自动发生。若不是,则我们需要重写 drawRect: 方法,在此方法中提供相应的绘制代码。


2.绘制周期

通常我们会设置一个标志,在每一轮的事件中扫描标志,看是否需要重新绘制,如果需要我们则调用 drawRect: 方法进行绘制。于是我们除了 drawRect: ,还有 setNeedsDisplaysetNeedsDisplayInRect: 方法供我们使用。他们分别的作用如下:

setNeedsDisplay:设置整个视图重新绘制。

setNeedsDisplayInRect::设置部分区域的视图重新绘制。


3.绘制 - Quartz 图形上下文

Quartz 图形上下文是包含绘制系统执行后,绘制命令所需要的信息,定义了各种基本的绘制参数,比如绘制使用的颜色、裁剪区域、线段的宽度及风格信息、文体信息、合成选项以及几个其他信息。

在调用 drawRect: 方法之前,视图对象会自动配置其绘制环境使代码能够立即执行进行绘制。作为这些配置的一部分,UIView 对象会为当前绘制环境创建一个图形上下文(对应于 CGContextRef 封装类型)。我们可以在 drawRect: 方法中通过 UIGraphicsGetCurrentContext()来获取和访问图形上下问对象,再对当前的图形进行定制的绘制。


4.绘制 - 具体实现

4.1 绘制一条直线
#import "BJView.h"

@implementation BJView

- (void)drawRect:(CGRect)rect {

    //获取图形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();

    //设置线条颜色
    CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);

    //设置线条宽度
    CGContextSetLineWidth(context, 2.f);

    //设置线条起点和终点的样式
    CGContextSetLineCap(context, kCGLineCapRound);

    //设置线条的转角的样式
    CGContextSetLineJoin(context, kCGLineJoinRound);


    // 绘制线方式 1
    //    CGContextMoveToPoint(context, 100, 120);
    //    CGContextAddLineToPoint(context, 150, 120);
    
    // 绘制线方式 2
    CGPoint apoint[2];
    apoint[0] = CGPointMake(100, 120);
    apoint[1] = CGPointMake(150, 120);
    CGContextAddLines(context, apoint, 2);

    //是否闭合路径
    //    CGContextClosePath(context);

    CGContextDrawPath(context, kCGPathFillStroke);
}

@end

效果:


直线


4.2 绘制一条折线(闭合且填充内容,相当于三角形)
#import "BJView.h"

@implementation BJView

- (void)drawRect:(CGRect)rect {

    //获取图形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();

    //设置边框颜色
    CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);

    //设置填充颜色
    CGContextSetRGBFillColor(context, 0, 1, 0, 1);

    //设置线条宽度
    CGContextSetLineWidth(context, 2.f);

    //设置线条起点和终点的样式
    CGContextSetLineCap(context, kCGLineCapRound);

    //设置线条的转角的样式
    CGContextSetLineJoin(context, kCGLineJoinRound);


    // 绘制线方式 1
    //    CGContextMoveToPoint(context, 100, 120);
    //    CGContextAddLineToPoint(context, 150, 120);
    //    CGContextAddLineToPoint(context, 150, 180);

    // 绘制线方式 2
    CGPoint apoint[3];
    apoint[0] = CGPointMake(100, 120);
    apoint[1] = CGPointMake(150, 120);
    apoint[2] = CGPointMake(150, 180);
    CGContextAddLines(context, apoint, 3);

    //闭合路径
    CGContextClosePath(context);

    CGContextDrawPath(context, kCGPathFillStroke);
}

@end

效果:


折线


4.3 绘制一个矩形
#import "BJView.h"

@implementation BJView

- (void)drawRect:(CGRect)rect {

    //获取图形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();

    //设置边框颜色
    CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);

    //设置填充颜色
    CGContextSetRGBFillColor(context, 0, 1, 0, 1);

    //设置线条宽度
    CGContextSetLineWidth(context, 2.f);

    //设置线条起点和终点的样式
    //    CGContextSetLineCap(context, kCGLineCapRound);

    //设置线条的转角的样式
    CGContextSetLineJoin(context, kCGLineJoinRound);

    // 通过绘制线的方式 1
    //    CGContextMoveToPoint(context, 100, 100);
    //    CGContextAddLineToPoint(context, 150, 100);
    //    CGContextAddLineToPoint(context, 150, 150);
    //    CGContextAddLineToPoint(context, 100, 150);

    // 通过绘制线的方式 2
    //    CGPoint apoint[4];
    //    apoint[0] = CGPointMake(100, 100);
    //    apoint[1] = CGPointMake(150, 100);
    //    apoint[2] = CGPointMake(150, 150);
    //    apoint[3] = CGPointMake(100, 150);
    //    CGContextAddLines(context, apoint, 4);

    // 绘制矩形方法
    CGContextAddRect(context, CGRectMake(100, 100, 50, 50));

    //闭合路径
    //    CGContextClosePath(context);

    CGContextDrawPath(context, kCGPathFillStroke);
}

@end

效果:


矩形


4.4 绘制一个圆(椭圆的特殊形态)
#import "BJView.h"

@implementation BJView

- (void)drawRect:(CGRect)rect {

    //获取图形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();

    //设置边框颜色
    CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);

    //设置填充颜色
    CGContextSetRGBFillColor(context, 0, 1, 0, 1);

    //设置线条宽度
    CGContextSetLineWidth(context, 2.f);

    //设置线条起点和终点的样式
    //    CGContextSetLineCap(context, kCGLineCapRound);

    //设置线条的转角的样式
    //    CGContextSetLineJoin(context, kCGLineJoinRound);
        
    // 绘制圆方法(其实所绘制的圆为所绘制用的Rect的矩形的内切圆,当宽度等于高度时,即为正圆)
    CGContextAddEllipseInRect(context, CGRectMake(100, 100, 200, 100));

    //闭合路径
    //    CGContextClosePath(context);

    CGContextDrawPath(context, kCGPathFillStroke);
}

@end

效果:



4.5 绘制一段圆弧(闭合且填充内容,相当于扇形)
#import "BJView.h"

#define arc(angle) ((angle)*(M_PI/180.0))

@implementation BJView

- (void)drawRect:(CGRect)rect {

    //获取图形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();

    //设置边框颜色
    CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);

    //设置填充颜色
    CGContextSetRGBFillColor(context, 0, 1, 0, 1);

    //设置线条宽度
    CGContextSetLineWidth(context, 2.f);

    //设置线条起点和终点的样式
    CGContextSetLineCap(context, kCGLineCapRound);

    //设置线条的转角的样式
    //    CGContextSetLineJoin(context, kCGLineJoinRound);
        
    // 绘制圆弧方法1 (参数由左至右分别是,图形上下文、圆心x、圆心y、半径、起始弧度、结束弧度、圆弧伸展的方向(0为顺时针,1为逆时针))
    CGContextAddArc(context, 150, 100, 100, arc(0), arc(160), 0);

    // 绘制圆弧方法2,由起始点、结束点分别与中间节点连线,同时以半径切过这两边则确定一段圆弧(不建议使用,因为理解不方便)
    // CGContextMoveToPoint(context, 100, 100);
    // CGContextAddArcToPoint(context, 150, 100, 150, 150, 50);

    //闭合路径
    CGContextClosePath(context);

    CGContextDrawPath(context, kCGPathFillStroke);
}

@end

效果:


圆弧


4.6 绘制一段文字
#import "BJView.h"

#define arc(angle) ((angle)*(M_PI/180.0))

@implementation BJView

- (void)drawRect:(CGRect)rect {

    NSString * str = @"BradleyJohnson";
    NSMutableDictionary * attributes = [NSMutableDictionary dictionary];
    attributes[NSFontAttributeName] = [UIFont systemFontOfSize:20];         attributes[NSForegroundColorAttributeName] = [UIColor purpleColor];
    attributes[NSBackgroundColorAttributeName] = [UIColor whiteColor];
    [str drawInRect:CGRectMake(100, 100, 200, 30) withAttributes:attributes];

}

@end

效果:


文字


4.6 绘制一张图片
#import "BJView.h"

@implementation BJView

- (void)drawRect:(CGRect)rect {

    UIImage * img = [UIImage imageNamed:@"bradleyJohnson.jpg"];
    
    // 在指定的范围内绘制图片,有可能引起图片拉伸
    [img drawInRect:rect];
}

@end

效果:


图片

5.绘制 - 贝塞尔曲线绘制

贝塞尔曲线,使用UIBezierPath类可以创建基于矢量的路径,这个类在UIKit中。它基本可以实现我们上面利用图形上下文做到的功能。



例如:

#import "BJView.h"

@implementation BJView

- (void)drawRect:(CGRect)rect {

    [[UIColor redColor] setStroke];    

    UIBezierPath * path = [UIBezierPath bezierPath];
    path.lineWidth = 2.0;
    path.lineCapStyle = kCGLineCapRound;
    path.lineJoinStyle = kCGLineJoinBevel;

    [path moveToPoint:CGPointMake(10, 20)];
    [path addLineToPoint:CGPointMake(50, 20)];

    [path closePath];

    [path stroke];
}

@end

这就可以轻易的绘制出一条直线,效果如图:

贝塞尔




同样的,我们也可以轻易的绘制出三角形、矩形、椭圆(圆)、圆弧如下:

#import "BJView.h"
#define arc(angle) ((angle)*(M_PI/180.0))

@implementation BJView

- (void)drawRect:(CGRect)rect {

    /* 三角形 */
    [[UIColor redColor] setStroke];

    UIBezierPath * path = [UIBezierPath bezierPath];
    path.lineWidth = 2.0;
    path.lineCapStyle = kCGLineCapRound;
    path.lineJoinStyle = kCGLineJoinBevel;

    [path moveToPoint:CGPointMake(10, 20)];
    [path addLineToPoint:CGPointMake(50, 20)];
    [path addLineToPoint:CGPointMake(50, 60)];

    [path closePath];

    [path stroke];
    
    /* 圆弧 */
    [[UIColor redColor] setStroke];

    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100,100) radius:100 startAngle:0 endAngle:arc(135) clockwise:YES];
    
    [path stroke];
    
    /* 矩形 */
    [[UIColor redColor] setStroke];

    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(20, 20, 100, 100)];
    
    [path stroke];
    
    /* 椭圆(圆) */
    [[UIColor redColor] setStroke];

    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20, 20, 100, 100)];
    
    [path stroke];
}

@end

当然最经典的就是,我们可以绘制二次和三次的贝塞尔曲线:

#import "BJView.h"

@implementation BJView

- (void)drawRect:(CGRect)rect {
    
    [[UIColor redColor] setStroke];

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:CGPointMake(20, 100)];

    // 绘制二次贝塞尔曲线
    //    [path addQuadCurveToPoint:CGPointMake(120, 100) controlPoint:CGPointMake(70, 150)];
    
    // 绘制三次贝塞尔曲线
    [path addCurveToPoint:CGPointMake(120, 100) controlPoint1:CGPointMake(45, 150) controlPoint2:CGPointMake(95, 50)];


    [path stroke];
}

@end

效果如下:


贝塞尔多次









如果你想要看到源码,可以到我的github上下载使用:Demo


如果你喜欢我的文章,请不要吝啬你的喜欢和关注,这是我的个人博客.

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

推荐阅读更多精彩内容