一、Quartz2D
Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac OS X系统(跨平台,纯 C 语言的)。包含在 Core Graphics 框架中。
Quartz 2D能完成的工作
绘制图形 : 线条\三角形\矩形\圆\弧等
- 绘制文字 微博图片上的水印
- 绘制\生成图片(图像)
- 读取\生成PDF
- 截图\裁剪图片 方型图片->圆型 四个角是透明的
- 自定义UI控件
注意:
- Quartz2D 是苹果官方的二维绘图引擎,同时支持 iOS 和 Mac OS X 系统。
- Cocos2D(Cocos2D-x、Cocos2D-iPhone、Cocos2D-HTML5等), Cocos2D 是一个第三方开源的2D游戏框架。做2D 游戏的 还有 Sprite Kit。 一般3D 游戏用 unity3D。
二、Quartz2D须知
- Quartz2D的API是纯C语言的
- Quartz2D的API来自于Core Graphics框架
- 数据类型和函数基本都以CG作为前缀
- CGContextRef
- CGPathRef
- CGContextStrokePath(ctx);
三、Quartz2D实例
Quartz 2D能做很多强大的事情,例如
裁剪图片
涂鸦\画板
涂鸦\画板
报表:折线图\饼状图\柱状图 (查看 gif 动画图片)
自定义view(自定义UI控件)(通过 Quartz2D绘制自己的控件)
通过继承自 UIView,重写 drawRect:方法实现在控件上绘制各种内容
举例:
- 通过继承自 UIView 实现自定义的 UIImageView
- 实现自定义的“下载进度条”控件
- 幸运转盘控件
四、Quartz2D 绘图主要步骤
- 获取【图形上下文】对象
- 向【图形上下文】对象中添加【路径】
- 渲染(把【图形上下文】中的图形会知道对应的设备上)
【图形上下文】= 草稿纸
- 获取草稿纸
- 向草稿纸画东西 画的东西约等于路径
- 按照草稿纸上的东西 画到自己真实想要画到的地方
五、图形上下文CGContextRef
- 图形上下文(Graphics Context):是一个CGContextRef类型的数据
- 图形上下文中主要包含如下信息
- 绘图路径(各种各样的图形)
- 绘图状态(颜色、线宽、样式、旋转、缩放、平移、图片裁剪区域等)
- 输出目标(绘制到什么地方去?UIView、图片、pdf、打印机等) (输出目标可以是PDF文件、Bitmap或者显示器的窗口上)
- 相同的一套绘图序列,指定不同的Graphics Context,就可将相同的图像绘制到不同的目标上 不同的上下文的类型,决定你的目标也不一样
Quartz2D提供了以下几种类型的Graphics Context:
- Bitmap Graphics Context
- PDF Graphics Context
- Window Graphics Context
- Layer Graphics Context(UI控件)
- Printer Graphics Context
六、使用 Quartz2D 绘图
方式一:直接调用 Quartz2D 的 API 进行绘图
- 代码量稍大
- 功能全面
- 步骤:
1> 获取绘图上下文
2> 把图形绘制到绘图上下文上
3> 把绘图上下文上的图形渲染到对应的设备上
方式二:调用 UIKit 框架封装好的 API 进行绘图
- 代码相对简单
- 只对部分 Quartz2D 的 API 做了封装
- 对于没有封装的功能只能调用 Quartz2D 原生 API
- 比如:画图片、文字到控件上。(UIKit 已经封装好了)
七、Quartz2D绘图的代码步骤
绘图方式一:
1. 获得图形上下文 C
CGContextRef ctx = UIGraphicsGetCurrentContext();
2. 拼接路径(下面代码是搞一条线段)
CGContextMoveToPoint(ctx, 10, 10); //起点
CGContextAddLineToPoint(ctx, 100, 100); //终点
CGContextAddLineToPoint(ctx, 150, 150); //连着的第三条线
//若需从其他起点开始画图 则继续 CGContextMoveToPoint
3. “渲染”(绘制路径)
CGContextStrokePath(ctx); // CGContextFillPath(ctx);
StrokeXxxx 表示画线(边线)(空心图形)
FillXxx 表示画填充的图形(实心图形)
绘图方式二:
CGPathRef 路径对象 创建一个可变路径对象 C
绘图方式三:
C + OC oc的path转换为c的path
绘图方式四:
C + OC c的path转换为oc的path 第一条线用c画 第二条线用OC画
绘图方式五:
纯OC
在渲染时 是会自动获取上下文 并将路径放在上下文当中
如何把c的转换为OC的 .CGpath
如何把oc的转换为C的
UIBezierPath 类的 类方法 :bezierPathWithCGPath
七、使用路径对象绘制图形(更简单)
UIBezierPath对象
- 1. 获取“图形上下文”对象
- 2. 创建 UIBezierPath 对象
- 3. 向 UIBezierPath 对象中绘制图形
- 4. 把 UIBezierPath 对象添加到上下文中
- 5. 把上下文对象渲染到设备上
注意: UIBezierPath 对象可以独立使用, 无需手动获取“图形上下文”对象
1.代码为什么要写在drawrect当中因为在这个方法当中可以获取到正确的上下文(与上下文有关,先获取当前上下文,上下文是系统创建好的,在其他方法中,可能会获取不到)。2.rect参数的含义当前view的bounds (x y width height) (rect参数是CGrect类型)3.drawrect 什么时候调用这个方法是系统调用1.当这个view第一次显示的时候会调用2.当这个view进程重绘的时候会调用4.如何重绘1.调用某个需要重绘的 view 对象的 setNeedsDisplay2.调用某个需要重绘的 view 对象的 setNeedsDisplayInRect rect:参数表示需要重绘的区域 (重绘类似于tableview的刷新)5.为什么不能手动调用 drawrect手动调用的时候可能获取不到正确的上下文调setNeedsDisplay 会自动调用drawrect
八、绘图顺序对最终结果的影响
九、在 UIView 上绘图
1. 获取与 UIView 相关的绘图上下文
-
在drawRect:方法中取得的上下文
-
在drawRect:方法中取得上下文后,就可以绘制东西到view上
View内部有个layer(图层)属性,drawRect:方法中取得的是一个Layer Graphics Context,因此,绘制的东西其实是绘制到view的layer上去了
View之所以能显示东西,完全是因为它内部的layer
十、drawRect:方法总结
- 为什么要实现drawRect:方法才能绘图到view上?
因为在drawRect:方法中才能取得跟view相关联的图形上下文
- drawRect:方法在什么时候被调用?
当view第一次显示到屏幕上时(加到UIWindow上显示出来)
重绘的时候:调用view的setNeedsDisplay或者setNeedsDisplayInRect:时
- drawrect 什么时候调用
当 view 第一次被显示的时候调用(调用一次) -
重绘事件被触发的时候, 调用 -
不要手动去调用这个方法, 否则可能无法正确的获取绘图上下文
- 如何重绘
手动调用重绘方法 setNeedsDisplay 或者 setNeedsDisplayInRect:
- rect参数的含义
参数 rect 表示当前 UIView 的 bounds
- 为什么要在 - (void)drawRect:(CGRect)rect 方法中进行绘图
只有在这个方法中才能获取当前 View 的绘图上下文
十一、通过自定义view来演示案例
如何利用Quartz2D自定义view?(自定义UI控件)
如何利用Quartz2D绘制东西到view上?
- 首先,得有图形上下文,因为它能保存绘图信息,并且决定着绘制到什么地方去
- 其次,那个图形上下文必须跟view相关联,才能将内容绘制到view上面
自定义view的步骤
- 新建一个类,继承自UIView
- 实现- (void)drawRect:(CGRect)rect方法,然后在这个方法中
- 取得跟当前view相关联的图形上下文
- 绘制相应的图形内容
- 利用图形上下文将绘制的所有内容渲染显示到view上面
十二、绘制基本图形练习
矩形:
圆角矩形:
用圆角矩形画圆:当半径为宽度的一半 正好是圆
当cornerRadius大于50(宽度的一半)的2/3 都是圆
椭圆:
拿椭圆画成圆 将宽和高设置成一样即可
圆 用圆弧的方式画圆
起始位置为0 则为3点钟方向
OC 中:
C中:
c和oc 画弧线的区别:
相同参数 圆弧方向相反?
c中 顺时针 逆时针的方向相反
圆弧
示例:
换颜色:
c
oc
可以混用
十三、几种不同的渲染方式
- 空心 StrokePath
- 实心 FillPath 和 EOFillPath (填充)
- 填充一个路径的时候,路径里面的子路径都是独立填充的。
- 假如是重叠的路径,决定一个点是否被填充,有两种规则
- 1,nonzero winding number rule(非零绕数规则),假如一个点被从左到右跨过,计数器+1,从右到左跨过,计数器-1,最后,如果结果是0,那么不填充,如果是非零,那么填充。
- 2,even-odd rule(奇偶规则),假如一个点被跨过1次,被跨过了奇数次,那么要被填充,被跨过偶数次则不填充,和方向没有关系
c:
oc:
even-odd rule:奇偶填充规则
被覆盖过奇数次的点填充,被覆盖过偶数次的点不填充
nonzero winding number rule:非零绕数规则
默认的填充规则,只需 KCGPathFill即可 从左往右跨过,+1 从右往左跨过 -1 最后如果为0 那么不填充 否则填充
1,表示先绘制的 2,表示后绘制的
两个圆心相同,半径不同的圆
射线 交点 奇数 填充 偶数 不填充
射线圆点的地方填充
addArcWithCenter 画圆弧函数
path.usesEvenOddFillRule = YES; 使用奇偶填充规则