Quartz 2D Programming Guide笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dolacmeng/article/details/78953245

Graphics Contexts图形上下文

图形上下文(graphics context)是绘制目标,可以理解为画布,包含着绘图时的参数和设备信息。类型为CGContextRef。获取graphics context后,调用Quartz 2D的函数进行绘制、旋转等操作,还可以修改如线宽、填充颜色等绘画参数。

获取图形上下文

当view出现在屏幕上以及视图将要更新时,系统会调用view的drawRect:方法。我们创建UIView子类,并重写drawRect:方法,此时调用UIKit提供的方法UIGraphicsGetCurrentContext,来获取系统为我们准备好的当前绘图环境的graphics context对象,。

路径

路径构成一个或多个图形或子路径。子路径可以由直线、曲线或两者相结合组成。如图:

这里写图片描述

调用CGContextMoveToPoint,传入表示x和y坐标的两个float值来确定路径的起始点。

CGContextMoveToPoint(context, 50, 50);

线段

两个点确定一条线,线的起点为当前点,所以只需要确定终点。
1、调用CGContextAddLineToPoint,传入终点坐标来添加一条线。

CGContextAddLineToPoint(context, 100, 50);

2、调用CGContextAddLines可以添加多条线,传入点的数组,Quartz以第一个点为起点,然后用直线依次连接剩下的点。

GPoint aPoints[3];//坐标点
aPoints[0] = CGPointMake(100, 80);//坐标1
aPoints[1] = CGPointMake(130, 150);//坐标2
aPoints[2] = CGPointMake(130, 200);//坐标3
CGContextAddLines(context, aPoints, 3);

【实例1】
Quartz 2D简单绘制分割线:https://www.jianshu.com/p/52700532f854

弧是圆的一部分,Quartz提供两个方法来创建弧。
1、CGContextAddArc,传入圆的中心点坐标(x,y)、半径、起始角度、结束角度、方向(1为时钟方向)。

CGContextAddArc(context, 100, 100, 50, M_PI_2 , 0, 1);

2、CGContextAddArcToPoint,传入两个终点的坐标值以及半径长度,Quartz以两个终点确定两条切线,从而确定弧。

【实例2】
可拖动的环形进度:http://blog.csdn.net/dolacmeng/article/details/46617517

曲线

二次和三次贝塞尔曲线可以确定各种各样的曲线形状,如图:

这里写图片描述

1、调用CGContextAddCurveToPoint函数,传入两个控制点、结束点,来确定一条三次贝塞尔曲线。

这里写图片描述

2、通过调用CGContextAddQuadCurveToPoint,传入控制点和结束点,确定一条二次贝塞尔曲线

这里写图片描述

【实例】贝塞尔曲线动画demo(仿美人相机效果):http://blog.csdn.net/dolacmeng/article/details/79276039

**实例中使用CAShapeLayer与UIBezierPath结合绘制,而非通过重写drawRect。UIBezierPath类可以创建基于矢量的路径,这个类在UIKit中,是Core Graphics框架关于path的一个封装。
CAShapeLayer和drawRect的比较:
- 1.drawRect:属于CoreGraphics框架,占用CPU,性能消耗大。
- 2.CAShapeLayer:属于CoreAnimation框架,通过GPU来渲染图形,节省性能。动画渲染直接提交给手机GPU,不消耗内存。
参考链接:https://www.jianshu.com/p/b1c38a3a67a9

闭合路径

调用CGContextClosePath,会添加一条从当前点到起始点的线来闭合当前的形状。

椭圆

椭圆是一个被压扁的圆形,调用CGContextAddEllipseInRect方法,传入一个用以确定椭圆边界的矩形。

CGContextAddEllipseInRect(context, CGRectMake(0, 0, 200, 100));

矩形

调用CGContextAddRect来添加一个矩形,传入一个包含原点坐标、宽度和高度的CGRect结构体。

CGContextAddRect(context, CGRectMake(0, 0, 200, 100));

可以一次添加多个矩形,只需调用CGContextAddRects方法,并传入CGRect结构体数组。

这里写图片描述

CGRect rects[4];
rects[0] = (CGRect){{0,0}, {50, 50}};
rects[1] = (CGRect){{100, 100}, {30, 30}};
rects[2] = (CGRect){{0,100}, {20, 20}};
rects[3] = (CGRect){{100,0}, {10, 10}};

CGContextAddRects(context, rects, 4);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillPath(context);

Creating a Path

创建路径:
在图形上下文中创建路径,先调用CGContextBeginPath.然后通过调用CGContextMoveToPoint设置起点。之后就绘制添加线、弧或曲线。总之记住:
* 在开始新路径前,调用CGContextBeginPath.
* 线、弧、曲线从当前点开始绘制,所以必须调用CGContextMoveToPoint来设置当前起始点或者调用对应的便捷方法。
* 当你想要闭合当前路径,调用 CGContextClosePath方法来连接上起始点。
* 当你绘制弧时,Quartz会在当前点和弧的起始点之间绘制一条直线。
* 最后需调用绘制函数来填充(fill)或画(stroke)出路径。
如:

CGContextMoveToPoint(context, 100, 100);
CGContextAddLineToPoint(context, 200, 200);
CGContextAddLineToPoint(context, 50, 300);
CGContextClosePath(context);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextStrokePath(context);

当路径被绘制出来后,路径会被清除。如果想要保存路径,Quartz提供了两种数据类型来创建可重复利用的路径:CGPathRef 和 CGMutablePathRef。但操作的是CGPath而不是graphics context:
* CGPathCreateMutable 代替 CGContextBeginPath
* CGPathMoveToPoint 代替 CGContextMoveToPoint
* CGPathAddLineToPoint 代替 CGContextAddLineToPoint
* CGPathAddCurveToPoint 代替 CGContextAddCurveToPoint
* CGPathAddEllipseInRect 代替 CGContextAddEllipseInRect
* CGPathAddArc 代替 CGContextAddArc
* CGPathAddRect 代替 CGContextAddRect
* CGPathCloseSubpath 代替 CGContextClosePath

Painting a Path

Quartz提供方法画出(画线)或填充路径,或者同时画出(画线)并填充路径。绘制的线条特性(宽度、颜色等)、填充颜色和计算填充区域的方式都是graphics state的一部分。

可以通过下表的属性,修改画出的路径特性。一旦修改这些属性,会作用于之后的所有绘制中。

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

line width是线条的宽度,路径两边各占线宽的一半。
line join表示Quartz怎么处理线条的连接处。Quartz支持的连接样式 如下:

这里写图片描述

line cap表示线的两个端点的样式:
这里写图片描述

line dash线条的样式:
这里写图片描述
Quartz提供的画线方法:

Function Description
CGContextStrokePath Strokes the current path.
CGContextStrokeRect Strokes the specified rectangle.
CGContextStrokeRectWithWidth Strokes the specified rectangle, using the specified line width.
CGContextStrokeEllipseInRect Strokes an ellipse that fits inside the specified rectangle.
CGContextStrokeLineSegments Strokes a sequence of lines.
CGContextDrawPath If you pass the constant kCGPathStroke, strokes the current path. See Filling a Path if you want to both fill and stroke a path.

Filling a Path

当填充路径时,Quartz认为每一个路径都是闭合的,然后利用这些闭合的路径计算填充区域。一共有两种计算填充区域的方式。椭圆形、矩形等简单的路径,很好确定填充区域。但是如果有重叠的路径或者路径内包含多个路径时(如下图),有两种规则来确定填充区域。

这里写图片描述

默认的填充规则为非零绕组规则:给定一条曲线C和一个点P,构造一条从P点出发射向无穷远的射线。找出所有该射线和曲线的交点,并按如下规则统计绕组数量(winding number):每一个顺时针方向(曲线从左向右通过射线)上的交点减1,每一个逆时针方向(曲线从右向左通过射线)上的交点加1。如果绕组总数为0,表示该点在曲线外;否则,该点在曲线内。

另一个为奇偶规则。平面内的任何一点P,引出一条射线,注意不要经过多边形的顶点,如果射线与多边形的交点的个数为奇数,则点P在多边形的内部,如果交点的个数为偶数,则点P在多边形的外部。
(参考:http://blog.csdn.net/wodownload2/article/details/52151714
【实例】中间透明的引导蒙层
http://blog.csdn.net/dolacmeng/article/details/79285679

Quartz提供的填充函数如下3-5:

Function Description
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.

Setting Blend Modes

重叠模式,两个绘制重叠时,重叠部分默认的颜色为:
result = (alpha * foreground) + (1 - alpha) * background

Clipping to a Path

路径可以作为遮罩,进行裁剪。例如有一张大图,但只希望显示其中一部分,可以设置裁剪区域,即只显示在闭合路径内部的部分:

CGContextBeginPath (context);
CGContextAddArc (context, w/2, h/2, ((w>h) ? h : w)/2, 0, 2*PI, 0);
CGContextClosePath (context);
CGContextClip (context);

提供的裁剪方法:

Function Description
CGContextClip Uses the nonzero winding number rule to calculate the intersection of the current path with the current clipping path.
CGContextEOClip Uses the even-odd rule to calculate the intersection of the current path with the current clipping path.
CGContextClipToRect Sets the clipping area to the area that intersects both the current clipping path and the specified rectangle.
CGContextClipToRects Sets the clipping area to the area that intersects both the current clipping path and region within the specified rectangles.
CGContextClipToMask Maps a mask into the specif

Transforms

在绘图前,可以通过变换矩阵(CTM)进行旋转、缩放、移动(可以理解为对坐标系操作),从而实现对即将绘制的图像进行变换。
下面的代码会把一张图片绘制到上下文:

CGContextDrawImage (myContext, rect, myImage);

这里写图片描述

调用CGContextTranslateCTM函数,改变坐标空间原点的x和y,如在x轴上移动100个单位,在y轴上移动50个单位:

CGContextTranslateCTM (myContext, 100, 50);

这里写图片描述

调用CGContextRotateCTM来旋转坐标系。如,旋转-45度:

CGContextRotateCTM (myContext, radians(–45.));

这里写图片描述

此时部分图片内容被裁剪了,因为这部分被移到图形上下文之外了。另外需要将角度转换为弧度:

include <math.h>

static inline double radians (double degrees) {return degrees * M_PI/180;}

调用CGContextScaleCTM可以在x轴和y轴上对坐标系进行缩放,如果为负值,可以进行翻转。例如在x轴上缩放0.5倍,在y轴上缩放0.75倍:

这里写图片描述

可以结合使用多个变换,通过CGContextConcatCTM方法可将多个变换组合成一个变换。

也可以直接依次执行多个变换。如:

CGContextTranslateCTM (myContext, w/4, 0);
CGContextScaleCTM (myContext, .25,  .5);
CGContextRotateCTM (myContext, radians ( 22.));

这里写图片描述

Creating Affine Transforms

仿射变换(affine transform)是作用于矩阵而非CTM。可以使用这些函数构造一个矩阵,然后通过函数CGContextConcatCTM应用于CTM。
仿射变换和CTM变换作用相同,都可以进行平移、旋转、缩放操作。方法和作用如下表:

Function Use
CGAffineTransformMakeTranslation To construct a new translation matrix from x and y values that specify how much to move the origin.
CGAffineTransformTranslate To apply a translation operation to an existing affine transform.
CGAffineTransformMakeRotation To construct a new rotation matrix from a value that specifies in radians how much to rotate the coordinate system.
CGAffineTransformRotate To apply a rotation operation to an existing affine transform.
CGAffineTransformMakeScale To construct a new scaling matrix from x and y values that specify how much to stretch or shrink coordinates.
CGAffineTransformScale To apply a scaling operation to an existing affine transform.

.
Quartz提供了CGAffineTransformInvert方法来撤消一个矩阵。但一般可以通过保存和还原graphics state实现类似的需求。

如果想要只对某个点或某部分进行变换,可以通过CGPointApplyAffineTransform方法对点,通过CGSizeApplyAffineTransform对某部分进行操作。

【待续…】

参考:
https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_overview/dq_overview.html

猜你喜欢

转载自blog.csdn.net/dolacmeng/article/details/78953245