iOS开发(高级特性)——Quartz2D

What is Quartz2D

UIView及其子类的应用目前比较熟悉了,下面开始学习一下Quartz2D。我们从名字上来大致猜测一下这个东西是干吗的,2D好说应该是说的2维和3D不同。那么Quartz又是个啥呢?Quartz的本意是石英石,也有石英表的意思。在Java中有个叫Quartz的开源的作业调度框架,估计是取其石英表的含义。但是在苹果开发中,这个名字到底怎么解释,还真猜不到。本来想望文知意的,结果不太靠谱,那我们直接先看一看苹果对Quartz 2D的描述

Quartz 2D is an advanced, two-dimensional drawing engine available for iOS application development and to all Mac OS X application environments outside of the kernel. Quartz 2D provides low-level, lightweight 2D rendering with unmatched output fidelity regardless of display or printing device. Quartz 2D is resolution- and device-independent; you don’t need to think about the final destination when you use the Quartz 2D application programming interface (API) for drawing.

The Quartz 2D API is easy to use and provides access to powerful features such as transparency layers, path-based drawing, offscreen rendering, advanced color management, anti-aliased rendering, and PDF document creation, display, and parsing.

The Quartz 2D API is part of the Core Graphics framework, so you may see Quartz referred to as Core Graphics or, simply, CG

这么一大段话,我们找几个关键字:drawing engine, resolution, device-independent, API。

这几个关键词加起来就是说,我们可以调用Quartz 2D的接口来绘图。至于后面的简单易用,功能强大这一类的描述,看看就好,不必较真。

我们已经知道了Quartz2D是什么,也知道它能干什么,接下来就是学习它是怎么做的。

When to use Quartz2D

讨论怎么用之前,我们先了解一下什么时候用,即应用场景。还是看苹果给的东西吧,毕竟这玩意都是他们搞出来的。

Draw graphics

Provide graphics editing capabilities in an application

Create or display bitmap images

Work with PDF documents

对这上面这几种翻译一下:

1 )画图

这里说的画图,应该是指在界面上画线条,多边形,弧形等。如股票软件中的各种线条。

2)提供图形编辑功能

图片编辑功能复杂一点,如照片处理一类的。

3)创建或者显示位图

4)处理PDF文档

How to use Quartz2D


concept

我们先理解一些概念,不然理解后面说的东西比较费劲。

1)Painter's model


图1

看图1来理解这个所谓的粉刷模型,就是一个粉刷效果,后面的掩盖前面的。

2)The Graphics Context

这个可以理解为绘画环境,比如涂鸦绘画环境就是墙壁,油画的绘画环境就是画布。开发中的绘画环境有:位图,PDF,窗口,图层。

Creating a Window Graphics Context,API本身不能获取window的Context,需要在Cocoa framework中获取一个。

CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];//

Creating a PDF Graphics Context

CGPDFContextCreateWithURL

CGPDFContextCreate

Creating a Bitmap Graphics Context

CGBitmapContextCreate

UIGraphicsBeginImageContextWithOptions//iOS环境中用这个,避免坐标系统的不同

3)Opaque Data Types

数据类型很多,我们用到的时候在详细了解。下面列一下这些数据类型和用处:

CGPathRef, used for vector graphics to create paths that you fill or stroke. SeePaths.

CGImageRef, used to represent bitmap images and bitmap image masks based on sample data that you supply. SeeBitmap Images and Image Masks.

CGLayerRef, used to represent a drawing layer that can be used for repeated drawing (such as for backgrounds or patterns) and for offscreen drawing. SeeCore Graphics Layer Drawing

CGPatternRef, used for repeated drawing. SeePatterns.

CGShadingRefandCGGradientRef, used to paint gradients. SeeGradients.

CGFunctionRef, used to define callback functions that take an arbitrary number of floating-point arguments. You use this data type when you create gradients for a shading. SeeGradients.

CGColorRefandCGColorSpaceRef, used to inform Quartz how to interpret color. SeeColor and Color Spaces.

CGImageSourceRefandCGImageDestinationRef, which you use to move data into and out of Quartz. SeeData Management in Quartz 2DandImage I/O Programming Guide.

CGFontRef, used to draw text. SeeText.

CGPDFDictionaryRef,CGPDFObjectRef,CGPDFPageRef,CGPDFStream,CGPDFStringRef,andCGPDFArrayRef, which provide access to PDF metadata. SeePDF Document Creation, Viewing, and Transforming.

CGPDFScannerRefandCGPDFContentStreamRef, which parse PDF metadata. SeePDF Document Parsing.

CGPSConverterRef, used to convert PostScript to PDF. It is not available in iOS. SeePostScript Conversion.

4)Coordinate Systems

在二维中绘图,坐标系的概念必不可少。指标系统大家还是比较熟悉的,过多的解释没有必要,值得注意的是在iOS的显示中坐标原点的位置不在左下角而在左上角。

5)Path

我们想要画一个三角形或一个圆,在现实中我们可以根据抽象的思维,随意画出三角形和圆,但是计算机怎样能够准确的画出我们想要的图案呢。Path就是用来定义图形的。可以理解为Path表示了图形的轮廓,按照这个轮廓,通过填充,描绘就可以准确的得到我们想要的图案。

直接在Context上画

CGContextMoveToPoint

CGContextAddLineToPoint

CGContextAddLines

CGContextAddArc

CGContextAddArcToPoint

CGContextAddCurveToPoint

CGContextAddQuadCurveToPoint

CGContextClosePath

CGContextAddEllipseInRect

CGContextAddRect

创建可复用的Path

CGPathCreateMutable, which replacesCGContextBeginPath

CGPathMoveToPoint, which replacesCGContextMoveToPoint

CGPathAddLineToPoint, which replacesCGContextAddLineToPoint

CGPathAddCurveToPoint, which replacesCGContextAddCurveToPoint

CGPathAddEllipseInRect, which replacesCGContextAddEllipseInRect

CGPathAddArc, which replacesCGContextAddArc

CGPathAddRect, which replacesCGContextAddRect

CGPathCloseSubpath, which replacesCGContextClosePath

将Path加到Context上CGContextAddPath.

有了Path了我们就可以涂鸦啦,哦不对,是Paint.有两种方式,填充(filling)和笔画(stroking)。

Parameters That Affect Stroking

Parameter:Function to set parameter value

Line width:CGContextSetLineWidth//线宽度

Line join:CGContextSetLineJoin//连接处的风格设置

Line cap:CGContextSetLineCap//两端的风格

Miter limit:CGContextSetMiterLimit //

Line dash pattern:CGContextSetLineDash

Stroke color space:CGContextSetStrokeColorSpace

Stroke color:CGContextSetStrokeColorCGContextSetStrokeColorWithColor

Stroke pattern:CGContextSetStrokePattern

Functions that fill paths

CGContextEOFillPath

Fills the current path using the even-odd rule.

CGContextFillPath

Fills the current path using the nonzero winding number rule.

CGContextFillRect

Fills the area that fits inside the specified rectangle.

CGContextFillRects

Fills the areas that fits inside the specified rectangles.

CGContextFillEllipseInRect

Fills an ellipse that fits inside the specified rectangle.

CGContextDrawPath

Fills the current path if you pass kCGPathFill(nonzero winding number rule) or kCGPathEOFill(even-odd rule). Fills and strokes the current path if you pass kCGPathFillStroke or kCGPathEOFillStroke.

6)Color and Color Space

颜色的相关内容。

7) Transform

如图,Transform说的就是这样的一些变换。缩放、移动,旋转等。有坐标系作为基础,这些变化对应相应的数学知识就很好理解了。简单的直接调用API即可,复杂的变换可能要涉及到数学内容,比如矩阵变换等,这些东西不在讨论范围。明白可能用到这些就好了


8)Partterns


9)Shadows

阴影可以让2D的图形有3D的视觉效果。

10)Gradient

有时候一种颜色,或者简单叠加的颜色看起来很枯燥乏味,我们用渐变让图形更丰富。

理解了这些东西了,也很无聊的了,来个例子吧,看看这些东西到底是怎么玩的。

@implementation MyQuartzView

- (id)initWithFrame:(NSRect)frameRect

{

self = [super initWithFrame:frameRect];

return self;

}

- (void)drawRect:(NSRect)rect

{

CGContextRef myContext = [[NSGraphicsContext

currentContext] graphicsPort]; // 1

// ********** Your drawing code here **********// 2

CGContextSetRGBFillColor (myContext, 1, 0, 0, 1);// 3

CGContextFillRect (myContext, CGRectMake (0, 0, 200, 100 ));// 4

CGContextSetRGBFillColor (myContext, 0, 0, 1, .5);// 5

CGContextFillRect (myContext, CGRectMake (0, 0, 100, 200));// 6

}

@end

得到的效果如图2

1.获取Context

2.准备绘图

3.设置填充颜色(涉及到Color相关内容)

4.填充矩形区域(涉及到path相关内容)

5.再次设置颜色(透明相关)

6.填充矩形区域(根据Painter's Model 覆盖,重叠区域的覆盖)

图2


Demo

1)QuartzLines

简单画线


-(void)drawInContext:(CGContextRef)context

{

// Drawing lines with a white stroke color

CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);

// Draw them with a 2.0 stroke width so they are a bit more visible.

CGContextSetLineWidth(context, 2.0);

// Draw a single line from left to right

CGContextMoveToPoint(context, 10.0, 30.0);

CGContextAddLineToPoint(context, 310.0, 30.0);

CGContextStrokePath(context);

// Draw a connected sequence of line segments

CGPoint addLines[] =

{

CGPointMake(10.0, 90.0),

CGPointMake(70.0, 60.0),

CGPointMake(130.0, 90.0),

CGPointMake(190.0, 60.0),

CGPointMake(250.0, 90.0),

CGPointMake(310.0, 60.0),

};

// Bulk call to add lines to the current path.

// Equivalent to MoveToPoint(points[0]); for(i=1; i < count,++i) AddLineToPoint(points[i]);

CGContextAddLines(context, addLines, sizeof(addLines)/sizeof(addLines[0]));

CGContextStrokePath(context);

CGPoint strokeSegments[] =

{

CGPointMake(10.0, 150.0),

CGPointMake(70.0, 120.0),

CGPointMake(130.0, 150.0),

CGPointMake(190.0, 120.0),

CGPointMake(250.0, 150.0),

CGPointMake(310.0, 120.0),

};

// Bulk call to stroke a sequence of line segments.

CGContextStrokeLineSegments(context, strokeSegments, sizeof(strokeSegments)/sizeof(strokeSegments[0]));  

cap and join

-(void)drawInContext:(CGContextRef)context

{

// Drawing lines with a white stroke color

CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);

// Preserve the current drawing state

CGContextSaveGState(context);

// Setup the horizontal line to demostrate caps

CGContextMoveToPoint(context, 40.0, 30.0);

CGContextAddLineToPoint(context, 280.0, 30.0);

// Set the line width & cap for the cap demo

CGContextSetLineWidth(context, self.width);

CGContextSetLineCap(context, self.cap);

CGContextStrokePath(context);

// Restore the previous drawing state, and save it again.

CGContextRestoreGState(context);

CGContextSaveGState(context);

// Setup the angled line to demonstrate joins

CGContextMoveToPoint(context, 40.0, 190.0);

CGContextAddLineToPoint(context, 160.0, 70.0);

CGContextAddLineToPoint(context, 280.0, 190.0);

// Set the line width & join for the join demo

CGContextSetLineWidth(context, self.width);

CGContextSetLineJoin(context, self.join);

CGContextStrokePath(context);

// Restore the previous drawing state.

CGContextRestoreGState(context);

// If the stroke width is large enough, display the path that generated these lines

if (self.width >= 4.0) // arbitrarily only show when the line is at least twice as wide as our target stroke

{

CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);

CGContextMoveToPoint(context, 40.0, 30.0);

CGContextAddLineToPoint(context, 280.0, 30.0);

CGContextMoveToPoint(context, 40.0, 190.0);

CGContextAddLineToPoint(context, 160.0, 70.0);

CGContextAddLineToPoint(context, 280.0, 190.0);

CGContextSetLineWidth(context, 2.0);

CGContextStrokePath(context);

}

}

-(void)setCap:(CGLineCap)c

{

if(c != _cap)

{

_cap = c;

[self setNeedsDisplay];

}

}

-(void)setJoin:(CGLineJoin)j

{

if(j != _join)

{

_join = j;

[self setNeedsDisplay];

}

}

-(void)setWidth:(CGFloat)w

{

if(w != _width)

{

_width = w;

[self setNeedsDisplay];

}

}



2)QuartzPoly

3)QuartzGradient

4)QuartzDash

5)QuartzPolygons

6)QuartzCurves

7)QuartzImages

8)QuartzRendering

9) QuartzClipping

2到9的内容就不一一贴代码和贴图了。这些内容不用记得太清楚,用的时候有个印象能快速查询到相关文档既可以了。

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

推荐阅读更多精彩内容