Write in the first
关于绘图,其实在我当前接触的项目中用得很少,但是以后肯定会接触到。
像这种不常用但比较重要的内容,我觉得要做到初步理解,然后梳理总结,到最后夯实基础、活学活用。所以写这篇文章。
iOS 系统本身提供了两大绘图的框架,即 UIKit 和 Core Graphics。UIKit
:像 UIImage(绘制图像)、NSString(绘制文本)、UIBezierPath(绘制形状)、UIColor。 这些类提供了功能有限但使用方便的方法来让我们完成绘图任务。一般情况下,UIKit就是我们所需要的。
Core Graphics
:CoreGraphics也称为Quartz 2D 是UIKit下的主要绘图系统,频繁的用于绘制自定义视图。Core Graphics是高度集成于UIView和其他UIKit部分的。Core Graphics数据结构和函数可以通过前缀CG来识别。
本篇文章主要从【iOS绘图 drawRect】学习总结,
在「时间 & 知识 」有限内,总结的文章难免有「未全、不足 」的地方,还望各位好友指出,以提高文章质量。
目录:
- 绘图基本概念
- 我是Core Graphics绘图
- UIBezierPath绘图概念
- 我是UIKit 之 UIBezierPath绘图
- 期待 & 后续
绘图基本概念
在学习绘图之前,我们先来了解一下几个基本的概念
属性 | 描述 |
---|---|
drawRect:(CGRect)rect | 作用:专门用来绘图 |
什么时候调用:当View显示的时候调用(ViewWillAppear和ViewDidAppear之间) | |
参数rect:当View的bounds,Note: 在drawRect方法当中系统已经帮你创建一个跟View相关联的上下文(Layer上下文),只要获取上下文就可以了 | |
什么操作调用:1、如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。2、该方法在调用sizeThatFits后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。3、通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0。 | |
Context | 定义:图形上下文,是一个CGContextRef类型的数据,你可以将图形上下文理解为一块画布 |
作用:1、保存绘图信息,绘图状态;2、决定绘制的输出目标(绘制到什么地方去?// 输出目标可以是PDF文件、Bitmap或者显示器的窗口上)3、相同的一套绘图序列,指定不同的 Graphics Context,就可将相同的图像绘制到不同的目标上 | |
path | 路径,ios绘图可以想象为你拿着一支笔去画图,画几条线或几个点从而形成一个路径,之后可以利用理解去填色或者描边 |
stroke、fill | 描边和填充,每个路径都需要填充或者描边后才能在视图中看见,他们都各自有很多样式可以设置,常见的有颜色、粗细、渐变,连接样式等等。 |
了解完上面的几个概念之后,我想 我们先不着急写的,首先你的知道你想实现什么效果用到什么属性值,及对属性值意思的理解。然后再结合下面的代码 就更容易理解和吸收了
Core Graphics绘图属性 | 描述 |
---|---|
UIGraphicsGetCurrentContext() | 获取上下文 |
CGContextMoveToPoint(ctx, x, y) | 设置起始点 |
CGContextAddLineToPoint(ctx, x, y) | 添加一根线到终点 |
CGContextAddLines(ctx, points, count) | 添加线(点之间) 参数:points点数组,count数组个数 |
CGContextAddEllipseInRect(ctx, CGRect rect) | 画椭圆,如果长宽相等就是圆 |
CGContextAddRect(ctx, CGRect rect) | 画矩形,长宽相等就是正方形 |
[image drawInRect:CGRect rect] | 画图片 |
[@”hello world” drawInRect:CGRect rect withAttributes:NSDictionary *dict] | 画文字 (属性值:NSFontAttributeName字体大小、NSForegroundColorAttributeName字体颜色) |
CGContextAddArc(ctx, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise) | 画圆 参数:圆心的x坐标,圆心的y坐标,圆的半径,开始弧度,结束弧度,0表示顺时针 1表示逆时针 |
CGContextAddQuadCurveToPoint(ctx, CGFloat cpx, CGFloat cpy, CGFloat x, CGFloat y); | 二次曲线函数 参数:控制点 x坐标,控制点 y坐标,终点 x坐标,终点 y坐标 Note:这里使用必须要设置起点MoveToPoin |
CGContextAddCurveToPoint(ctx, CGFloat cp1x, CGFloat cp1y, CGFloat cp2x, CGFloat cp2y, CGFloat x, CGFloat y) | 三次曲线函数 参数:控制点1 x y坐标,控制点2 x y坐标,终点 x坐标,终点 y坐标 Note:这里使用必须要设置起点MoveToPoin |
CGContextStrokePath(ctx) | 渲染上下文(Stroke描边,空心) |
CGContextFillPath(ctx) | 渲染上下文(Fill填充,实心) |
CGContextDrawPath(ctx, CGPathDrawingMode mode) | 渲染上下文 mode:1、kCGPathFill 只有填充(非零缠绕数填充),不绘制边框 2、kCGPathEOFill 奇偶规则填充(多条路径交叉时,奇数交叉填充,偶交叉不填充)3、kCGPathStroke 只有边框 4、kCGPathFillStroke 既有边框又有填充 5、kCGPathEOFillStroke 奇偶填充并绘制边框 |
其他属性设置 | |
CGContextSetStrokeColorWithColor(ctx, Color) | 设置线颜色 |
CGContextSetFillColorWithColor(ctx, Color) | 设置填充色 |
CGContextSetLineWidth(ctx, CGFloat width); | 设置线宽度 |
CGContextSetLineJoin(ctx, CGLineJoin join) | 设置连接样式(kCGLineJoinMiter尖的、斜接, Round圆, Bevel斜面) |
CGContextSetLineCap(ctx, CGLineCap cap) | 设置顶角样式(kCGLineCapButt, Round, Square) |
CGContextSetLineDash(ctx, CGFloat phase, lengths, count) | 设置虚线样式(参数:phase虚线从那开始绘制;lengths C语言的数组,举个例子: 声明一个数组 CGFloat dash[] = @{3.0, 1.0}意思就是长度为3.0 间隙长度为1.0,以此类推;count lengths数组的个数) |
示例代码:自定义View的步骤
新建一个类,继承UIView
实现- (void)drawRect:(CGRect)rect
方法
我是Core Graphics绘图
1、获取上下文
2、绘制路径
3、添加路径到上下文
4、渲染上下文(描边或填充)
|
|
PS.
第一个方法写的比较详细,写了使用直接画线的方式 和 path的方式。推荐使用path的方式画线。 另外,第一个方法也写了移动笔触画线和用点集合画线。后面方法只会涉及其中一种,因为方法都比较类似
画线
画矩形,画椭圆,多边形
画图片、画文字
画圆、圆弧
Core Graphics绘图效果:
UIBezierPath绘图概念
同样,首先你的知道你想实现什么效果用到什么属性值,及对属性值意思的理解。然后再结合下面的代码 就更容易理解和吸收了
UIKit 之 UIBezierPath绘图属性 | 描述 |
---|---|
[UIBezierPath bezierPath] | 创建路径 |
moveToPoint:(CGPoint) | 设置起点 |
addLineToPoint:(CGPoint) | 添加一根线到终点 |
[[UIColor redColor] set] | 设置线颜色(注意:如果使用 setStroke 和 setFill 与渲染方式要相对应) |
addQuadCurveToPoint:(CGPoint) controlPoint:(CGPoint) | 画曲线(controlPoint:弯曲方向点) |
bezierPathWithRect:(CGRect) | 画矩形 |
bezierPathWithRoundedRect:(CGRect) cornerRadius:(CGFloat) | 画圆角矩形 |
bezierPathWithOvalInRect:(CGRect) | 画圆(Width = Height)、画椭圆(Width != Height) |
bezierPathWithArcCenter:(CGPoint) radius:(CGFloat) startAngle:(CGFloat) endAngle:(CGFloat) clockwise:(BOOL) | Center:弧所在的圆心(这里不能直接用self.center,因为它是相对于它的父控件的,采用rect 宽度0.5、高度0.5),radius:圆的半径,startAngle:开始角度, endAngle:结束角度,clockwise:YES顺时针 NO逆时针 |
bezierPathWithArcCenter:(CGPoint) radius:(CGFloat) startAngle:(CGFloat) endAngle:(CGFloat) clockwise:(BOOL) | [path addLineToPoint:center]; 注:1、[path closePath] 从路径终点连接一根线到路径的起点,2、[path fill] 填充之前,会自动关闭路径 |
UIGraphicsBeginImageContextWithOptions | 开启上下文(size:上下文大小, opaque:透明度(YES透明,NO不透明), scale:图片质量,一般为0和当前设备的分辨率一样) |
drawAtPoint:(CGPoint) | 图片绘制到上下文 |
addClip | 设置成裁剪区域 |
drawAtPoint:(CGPoint) blendMode:(CGBlendMode) alpha:(CGFloat) | 图片绘制到上下文 |
drawAtPoint:(CGPoint) withAttributes:NSDictionary *dict) | 文字绘制到上下文(属性值:NSFontAttributeName字体大小、NSForegroundColorAttributeName字体颜色) |
UIGraphicsEndImageContext() | 关闭上下文 |
[path stroke] / [path fill] | 底层做了:1.获取上下文->2.绘制路径->3.添加路径到上下文->4.渲染上下文 |
PS.
同样第一个方法写的比较详细,且有注释
实现- (void)drawRect:(CGRect)rect
方法
我是UIKit 之 UIBezierPath绘图
1、获取上下文
2、绘制路径
3、添加路径到上下文
4、渲染上下文(描边或填充)
|
|
画直线
画矩形、椭圆
画弧度、扇形
画图片和文字
效果:
如果你想更深入学习 UIBeizerPath ,这里有一篇官方译文加原理的总结 ,👍推荐一篇 UIBezierPath译文+活用
期待
- 如果在阅读过程中遇到 error || new ideas,希望你能 messages 我,我会及时改正谢谢。
- 点击右上角的 喜欢 和 订阅Rss 按钮,可以收藏本仓库,并在 Demo 更新时收到邮件通知。