Core Graphics框架 : 一个让程序猿成为视觉设计师的框架


Core Graphics简介


说Core Graphics框架之前,我们首先要先说一下,在iOS中绘制图形的方式,其形式主要有三种.

  • 1.创建一个UI视图,并且使用"drawRect:"方法添加到Quartz 2D绘制代码中,也就是今天所要说的Core Graphics框架.
  • 2.使用Core Animation层,并且通过委托方法想Core Animation层提供图形内容.
  • 3.通过 OpenGL ES 渲染图形

其结构图如下所示.从图中我们看到的是是不管使用者还是开发者最容易接触到的先是UIKit框架,然后再就是Core Graphics,Core Animation和OpenGL ES,Core Graphics,Core Animation这两个框架虽然我们没有用过,但是我们最少听过,但是OpenGL ES是什么鬼?OpenGL ES这个有点日后再议,今天主题不是它,而是我们的Core Graphics框架.
</b>
Core Graphics其实是一套基于C语言的API框架,使用了Quartz作为绘图引擎。这也就意味着Core Graphics不是面向对象的。但是这句话对我们并无伤大雅.也就是然并卵~,我们只需要知道如何使用Core Graphics框架就好.下面我就对Core Graphics框架相关知识一一道来.


CGContextRef (图形上下文)


图形上下文,不要被它的名字吓到,其实你就可以理解为是一个画布,我们要绘制任何东西总要有个东西接受我们绘制的东西吧?所以CGContextRef就出现了,对于CGContextRef有几个注意点,iOS是允许新建CGContextRef的,但是我们通常不这么干,因为创建一个新的CGContextRef,但是性能和内存的使用上,效率是非常低的。所以我们会在"drawRect:"方法中直接获取当前View的CGContextRef.代码如下.

    //获取当前View的图形上下文
    CGContextRef contextRef = UIGraphicsGetCurrentContext();


CGPath(路径)


那么画板有了,我们是不是应该可以作图了?是的,但是如何才能确定出一个图形呢?不管是什么图形,首先我们要先确定它的边框,一旦确定了一个边框,我们就可以设置边框的各种绘图属性、边框内部区域的绘图属性、绘制边框还是内部区域等。这时候,CGPath就闪亮登场了.CGPath也就是路径信息,一开始如果没有接触过PS过的童鞋可能不知道路径到底是一个什么,通俗一点讲,不管你画什么图形,直线也好,多边形也罢,你的画笔都要从一个开始位置开始,然后 "持续"移动画笔,画出一个图形来.终止于一个结束点,如果画笔为无色,画笔划过的线可以理解为路径.当然了,现实中哪有无色的画笔?哈哈.好了言归正传.Core Graphics框架其实已给我们分装好了很多的调用函数,方便我们调用,我们就看几个常用调用函数.

新建路径(常用于创建直线,也可以用直接拼接成多边形)

CGMutablePathRef path = CGPathCreateMutable();

新建矩形,rect是矩形的位置和大小信息,transform是仿射变换参数.

CGPathCreateWithRect(CGRect rect,const CGAffineTransform * __nullable transform)

新建圆,rect是圆的位置和大小信息,cornerWidth和cornerHeight是圆的半径,通过设置这两个参数,我们可以生成椭圆,transform是仿射变换参数.

CGPathCreateWithRoundedRect(CGRect rect,CGFloat cornerWidth, CGFloat cornerHeight,const CGAffineTransform * __nullable transform)

把路径添加到图形上下文中,c是图形上下文参数,path是路径参数.这里有一点要注意,如果你创建好路径,并且调用下面添加方法,我们在View页面上是看不到的路径,这是为什么呢?还记得我们前面说用"无色"的画笔做出的图形,可以理解为路径.就是因为没有涂色,所以看不见.

CGContextAddPath(CGContextRef __nullable c,CGPathRef __nullable path)

绘制路径函数,我们把路径的属性设置完成之后,就需要绘制函数,记住添加和绘制是两回事~~~.c代表着图形上下文.mode代表着填充类型.

CGContextDrawPath(CGContextRef __nullable c,  CGPathDrawingMode mode)

释放删除路径函数,有人就会问,我们在ARC开发环境下,会自动释放呀,NONONO~~,因为CGPathCreateMutable方法返回的路径是一个Core Fundation Object.而这并不在ARC的管理范围之内.所以需要使用下面函数手动释放对象. path代表着要删除的路径.

CGPathRelease(CGPathRef __nullable path)


CGAffineTransform(仿射变换)


那么,就算我们已经已经做好了图形了,可能我们需要对图形做平移,缩放,旋转的时候,我们该如何实现?CGAffineTransform是一个仿射变换的结构体,专门用于进行二维平面的几何变换(平移,旋转,缩放).而且比较贴心的是系统(到底是系统还是程序猿?😂)已经帮我们分装了一些函数,我们不需要直接设置CGAffineTransform,直接调用函数即可,下面我们就看一下CGAffineTransform的结构体形式以及一些常用的仿射变换函数.常用函数有一个地方要注意,就是不管是哪一种仿射变换,都有两个函数,一个是在初始的状态上进行变换,一个是在前一个状态上进行变换.

CGAffineTransform的结构体如下所示,如果想要了解CGAffineTransform就要引入齐次函数的概念,这个以后再说.

struct CGAffineTransform {
  CGFloat a, b, c, d;
  CGFloat tx, ty;
};

平移函数,tx和ty代表着偏移量.

 CGAffineTransformMakeTranslation(CGFloat tx,CGFloat ty)

缩放函数,sx和sy代表着x轴和y轴的缩放比例.

CGAffineTransform CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)

旋转函数,angle代表着旋转的角度.逆时针为正,顺时针为负。

CGAffineTransformMakeRotation(CGFloat angle)


文字的绘制


上面我们看了一下如何创建多边形,那么显示当中不但有图形还会出现文字,文字我们又该如何处理呢?文字的绘制比较简单,我们只要直接使用需要绘制的字符串直接调用drawInRect:drawAtPoint:这两个方法即可.具体内容以后再说,这篇我们只做简单的了解.下面我们就对这两个绘制方法进行简单的介绍.

rect代表着绘制的文字的大小和位置信息.attrs代表着文本属性.

- (void)drawInRect:(CGRect)rect withAttributes:(nullable NSDictionary<NSString *, id> *)attrs 

point代表着绘制的文字的大小信息.attrs代表着文本属性.

- (void)drawAtPoint:(CGPoint)point withAttributes:(nullable NSDictionary<NSString *, id> *)attrs 


重新绘制.


我们知道绘制整体过程是在View的- (void)drawRect:(CGRect)rect;方法中进行.如果我们想要重新绘制图形该如何办呢?我们并不会直接调用drawRect:这个绘制方法,而是调用如下方法.

//重新绘制.
- (void)setNeedsDisplay;


从Core Graphics框架到Hello World


上面喋喋不休的讲了一大堆,可能童鞋早已擦拳磨掌准备大干一场了.接下来我们就开始Hello World吧.

首先,我们在工程中新建一个UIView对象.这里我创建的是SDView,大家可自行设定.

创建好了UIView对象之后,我们就在SDView.h的- (void)drawRect:(CGRect)rect;方法中进行绘制工作,首先我们要先获取View的图形上下文.毕竟自己创建的效率低嘛~

    //获取上下文
    CGContextRef contextRef = UIGraphicsGetCurrentContext();

获取完成之后,Hello World之路就从一条直线开始吧,首先我们先设置创建一个路径.

    //创建路径
    CGMutablePathRef path = CGPathCreateMutable();

创建完路径,我们就设置路径的起始位置和终点位置,并且把它添加上图形上下文上.

    CGPathMoveToPoint(path, nil, 100, 100);
    
    CGPathAddLineToPoint(path, nil, 200, 200);
    
    CGContextAddPath(contextRef, path);

如果现在路径已经做好了,是一条从(100,100)到(200,200)的直线.并且已经添加到图形上下文中了.这时候如果我们直接绘制并不能看到我们的路径这是为什么呢?还是因为"无色"呀,没有设置颜色,我们怎么会看到.所以下面我们就对路径的属性进行相关的设置.

上图中,笔触颜色为红色,其实也就是边框的颜色,因为直线只是一条直线,所以我们设置它的笔触颜色即可.设置代码如下,我们需要输入的是RGB值.

    CGContextSetRGBStrokeColor(contextRef, 1.0, 0, 0, 1);//设置笔触颜色

下面这行代码是设置填充色,意思是填充路径圈起来的内部颜色.直线设置也无伤大雅,因为没有圈起来任何区域,像多边形,就能看出效果来了.

    CGContextSetRGBFillColor(contextRef, 0, 1.0, 0, 1);//设置填充色

设置线条的宽度,如果不进行设置,默认好像设置为1.0

    CGContextSetLineWidth(contextRef, 5.0);//设置线条宽度

对于设置顶点样式和连接点样式,我们需要注意的是它的概念,顶点就是两头的点,即开始节点和终止节点.连接点呢,即为中间转折点,比如创建矩形,就会产生两个连接点.

    CGContextSetLineCap(contextRef, kCGLineCapButt);//设置顶点样式
    CGContextSetLineJoin(contextRef, kCGLineJoinRound);//设置连接点样式

上面呢,我们已经把属性设置完成了,接下来就是绘制了.

绘制路径,因为我们只需要绘制路径部分,所以我们的填充类型选择是kCGPathFillStroke;

    CGContextDrawPath(contextRef, kCGPathFillStroke);//最后一个参数是填充类型
    

最后,我们需要手动释放我们的路径.原因看路径相关部分.

    CGPathRelease(path);

这样整体的Hello world绘制部分就完成了,现在我们需要在ViewController中调用一下,看看我们的绘制成果.代码如下.

#import "ViewController.h"
#import "SDView.h"

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    SDView *view = [[SDView alloc]initWithFrame:self.view.frame];
    view.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:view];

}

@end

最后command +R运行一下,看一下效果图,我们成功的绘制出了我们第一条直线.


Core Graphics优势


说了这么多,现在我们只是知道Core Graphics框架是iOS实现图像的一种方式,但是什么要深入的研究Core Graphics呢?或者说Core Graphics直接绘图有着这样的优势呢?

因为Core Graphics更接近底层,越接近底层就越快速越高效.这自是不用多说,同时呢,使用Core Graphics可以大大减少应用程序的大小,这又是从何说起呢?举个例子来说,如下图所示.我们现在要在屏幕上显示一个文字,通常我们会怎么干呢?我们会先创建一个UILabel对象,然后把文字添加上,我们需要绘制的部分是UILable对象和文字两部分,现在,我们使用Core Graphics可以只绘制文字这一部分,对系统内存的损耗大大减少.再就是仿射变换结构体的存在,我们可以对绘制的部分进行一些平移,缩放,旋转等操作.


</br>


恩恩,Core Graphics框架 ,一个让程序猿成为视觉设计师的框架,hello world之路就到这了.最后附上本文的Demo.后期,我会对Core Graphics框架中所遇到的相关知识进行详细的分析解说,希望大家继续关注骚栋.

--->传送门💾

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

推荐阅读更多精彩内容