iOS 绘图API之Core Graphics系统学习(一)

前言

  iOS支持两套图形API族:Core Graphics和OpenGL ES。OpenGL ES是跨平台的图形API,属于OpenGL的一个简化版本。而QuartZ 2D是苹果公司开发的一套API,它是Core Graphics Framewore的一部分。
  本文中主要是对Core Graphics框架的学习总结。

  对于一个初学者来说,UIKit和Core Graphics两个支持绘图的框架常常令我们感到迷惑。

UIKit

  UIKit是一组Objective-C API,为线条图形、Quartz图像和颜色操作提供Objective-C封装,并提供2D绘制、图像处理及用户接口级别的动画。
  UIKit包含UIBezierPath(绘制线、角度、椭圆及其它图形)、UIImage(显示图像)、UIColor(颜色操作)、UIFont和UIScreen(提供字体和屏幕信息)等类,它在位图图形环境、PDF图形环境上进行绘制和操作功能,也提供对标准视图的支持,也提供对打印功能的支持。
  使用UIKit,你只能在当前上下文中绘图。

Core Graphics

  这是一个绘图专用的API族,它经常被称为QuartZ或者QuartZ 2D。Core Graphics 是iOS上所有绘图功能的基石,包括UIKit(UIKit是对Core Graphics的进一步封装)。
  使用Core Graphics之前需要指定一个用于绘图的图形上下文(CGContextRef),这个图形上下文会在每个绘图函数中都会用到。

  至此,我们了解了这两个框架的基本关系,而这两个框架中都提到了图形上下文(图形场景)。获得一个图形上下文是我们完成绘图任务的第一步,可以将图形上下文理解为一块画布。那么下边介绍三种获得图形上下文的方法:

- (void)drawRect:(CGRect)rect方法

  在此方法中,UIKit框架可以直接绘图,而Core Graphics可以通过UIGraphicsGetCurrentContext函数获取当前的图形上下文。

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx

  在此方法中,直接传入了图形上下文,但是该上下文不一定是当前的图形上下文,所以在UIKit框架下绘图时,需要调用UIGraphicsPushContext()函数将该上下文变为当前上下文,结束时调用UIGraphicsPopContext()函数还原上下文。而Core Graphics框架下可以直接使用该上下文。

UIGraphicsBeginImageContextWithOptions函数

  此函数获取图形上下文的规则跟drawRect:方法是一样的。利用该上下文,你就可以在其上进行绘图,并生成图片。调用UIGraphicsGetImageFromCurrentImageContext函数可从当前上下文中获取一个UIImage对象。记住在你所有的绘图操作后别忘了调用UIGraphicsEndImageContext函数关闭图形上下文。
  这里主要解释一下三个参数的含义。第一个参数表示所要创建的图片尺寸;第二个参数用来指定生成图片的背景是否为不透明,YES表示不透明,则得到的是黑色的背景;第三个参数制定生成图片的缩放因子,这个缩放因子与UIImage的scale属性所指的含义是一致的。0则表示让图片的缩放因子根据屏幕的分辨率而变化。

基于两大绘图框架和三种获取图形上下文的方法的六种绘图形式

举例说明:绘制一个蓝色的圆
第一种绘图形式:基于UIKit框架(即使用UIBezierPath)在UIView的子类方法drawRect:中实现。

- (void) drawRect: (CGRect) rect {
   UIBezierPath* p = [UIBezierPathbezierPathWithOvalInRect:CGRectMake(0,0,100,100)];
   [[UIColor blueColor] setFill];
   [p fill];
}

第二种绘图形式:基于Core Graphics框架在UIView的子类方法drawRect:中实现。

- (void) drawRect: (CGRect) rect {
    CGContextRef con = UIGraphicsGetCurrentContext();
    CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100));
    CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor);
    CGContextFillPath(con);
}

第三种绘图形式:基于UIKit框架(即使用UIBezierPath) 在UIView的子类方法drawLayer:inContext:中实现。

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
    [super drawLayer:layer inContext:ctx];
    UIGraphicsPushContext(ctx);
    UIBezierPath* p = [UIBezierPathbezierPathWithOvalInRect:CGRectMake(0,0,100,100)];
    [[UIColor blueColor] setFill];
    [p fill];
    UIGraphicsPopContext();
}

PS:同时此方法必须重写drawRect:方法,否则上边的方法不会被调用。
详细了解这块的调用逻辑可以看这篇文章
iOS的绘图之drawRect和drawLayer:inContext
第四种绘图形式: 使用Core Graphics在drawLayer:inContext:方法中实现同样操作,代码如下:

- (void)drawLayer:(CALayer*)lay inContext:(CGContextRef)con {
    CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100));
    CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor);
    CGContextFillPath(con);
}

  最后,演示UIGraphicsBeginImageContextWithOptions的用法,并从上下文中生成一个UIImage对象。生成UIImage对象的代码可以在任何地方被使用,它没有上述绘图方法那样的限制。

第五种绘图形式: 使用UIKit实现:

UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0);
UIBezierPath* p = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,100,100)];
[[UIColor blueColor] setFill];
[p fill];
UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

第六种绘图形式: 使用Core Graphics实现:

UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0);
CGContextRef con = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100));
CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor);
CGContextFillPath(con);
UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

UIKit和Core Graphics可以在相同的图形上下文中混合使用。在iOS 4.0之前,使用UIKit和UIGraphicsGetCurrentContext被认为是线程不安全的。而在iOS4.0以后苹果让绘图操作在第二个线程中执行解决了此问题。

写在最后的话

从开始研究这个框架看了很多文章,收获很多,慢慢从这些文章中一点点的找到它们之间的关系,这个过程是曲折的,但也是喜悦的。后续还会更新,本篇文章只是开始,一点点皮毛。

借鉴的文章

iOS 图形编程总结
iOS绘图教程
iOS绘图框架CoreGraphics分析

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

推荐阅读更多精彩内容

  • Core Graphics Framework是一套基于C的API框架,使用了Quartz作为绘图引擎。它提供了低...
    ShanJiJi阅读 1,513评论 0 20
  • 原文地址:http://www.cocoachina.com/industry/20140115/7703.htm...
    默默_David阅读 6,098评论 0 1
  • Core Graphics Framework是一套基于C的API框架,使用了Quartz作为绘图引擎。它提供了低...
    苏宇lovecc阅读 705评论 0 2
  • 缓了几日没动静,报章没新闻,没人再找他们麻烦,就连公司的业务也出奇的顺利。便找师傅选了黄道吉日,妥妥当当安排了千佑...
    籽盐阅读 316评论 0 0
  • 每个人人生当中都会经历无数次选择,不同的选择造就了不同的人生,如何做出最优选择,如何避开不利选择,这就变成...
    陌上可妍阅读 729评论 0 2