什么是Quartz2D
Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统
作用
1
2
3
4
5
6
7
8
9
|
<code>Quartz
绘制图形
绘制文字
绘制生成图片(图像)
读取生成PDF
截图裁剪图片
自定义UI控件
…
</code>
|
Quartz2D在iOS开发中的价值
为了便于搭建美观的UI界面,iOS提供了UIKit框架,里面有各种各样的UI控件 UILabel:显示文字 UIImageView:显示图片
UIButton:同时显示图片和文字(能点击)
… …利用UIKit框架提供的控件,拼拼凑凑,能搭建和现实一些简单、常见的UI界面
但是,有些UI界面极其复杂、而且比较个性化,用普通的UI控件无法实现,这时可以利用Quartz2D技术将控件内部的结构画出来,自定义控件的样子 其实,iOS中大部分控件的内容都是通过Quartz2D画出来的,因此,Quartz2D在iOS开发中很重要的一个价值是:自定义view(自定义UI控件)
基本图形绘制
线段(线宽、线段样式、线条颜色)
1
2
3
|
<code>注意点:画线条只能通过空心样式画。
CGContextStrokePath(ctx);
</code>
|
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<code class = "hljs"
"" >-( void )drawLine
{
//1.获得图形上下文
CGContextRef
//2.拼接图形(路径)
//画一条直线
//设置起始位置
CGContextMoveToPoint(ctx, 10 , 10 );
//添加一条线段到点(100,100)
CGContextAddLineToPoint(ctx, 100 , 100 );
//设置直线的宽度(黄色)
//CGContextSetRGBStrokeColor(ctx,
//set
//stroke
//fill
[[UIColor
//设置直线的宽度
CGContextSetLineWidth(ctx, 10 );
//设置直线开头的样式(圆)
CGContextSetLineCap(ctx,
//设置直线转折点的样式(圆)
CGContextSetLineJoin(ctx,
//3.渲染显示到View上面
CGContextStrokePath(ctx);
}</code>
|
三角形
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<code class = "hljs"
"" >-( void )drawTriangle
{
//1.获得图形上下文
CGContextRef
//2.拼接图形(路径)
//画一个三角形
//设置起始位置
CGContextMoveToPoint(ctx, 0 , 0 );
//添加一条线段到点(100,100)
CGContextAddLineToPoint(ctx, 100 , 100 );
CGContextAddLineToPoint(ctx, 120 , 20 );
CGContextClosePath(ctx);
//设置直线的宽度(红色)
[[UIColor
//设置直线的宽度
CGContextSetLineWidth(ctx, 10 );
//设置直线转折点的样式(切面)
CGContextSetLineJoin(ctx,
//3.渲染显示到View上面
CGContextStrokePath(ctx);
}</code>
|
矩形(空心、实心、颜色)
多种方法画矩形
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
<code class = "hljs"
"" >
//
CGContextRef
//
CGContextMoveToPoint(ctx, 10 , 10 );
CGContextAddLineToPoint(ctx, 100 , 10 );
CGContextAddLineToPoint(ctx, 100 , 100 );
CGContextAddLineToPoint(ctx, 10 , 100 );
CGContextClosePath(ctx);
//3.渲染
CGContextStrokePath(ctx);
*方式二
//
CGContextRef
//
CGContextAddRect(ctx, 10 , 10 , 100 , 100 ));
//3.渲染
CGContextStrokePath(ctx);
*
//
CGContextRef
//
CGContextStrokeRect(ctx, 10 , 10 , 100 , 100 ));
*
//
CGContextRef
//
CGMutablePathRef
CGPathAddRect(path,NULL, 10 , 10 , 100 , 100 ));
//
CGContextAddPath(ctx,
CGPathRelease(path);
//
CGContextStrokePath(ctx);
*
UIBezierPath 10 , 10 , 100 , 100 )];
[path
</code>
|
椭圆圆圆弧饼状图
画圆弧方法说明:
1
2
3
4
5
6
7
8
9
|
<code class = "hljs"
"" > void
CGContextRef
CGFloat //圆心的x坐标
CGFloat //圆心的x坐标
CGFloat //圆的半径
CGFloat //开始弧度
CGFloat //结束弧度
int
//0表示顺时针,1表示逆时针
);</code>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<code class = "hljs"
"" >
-( void )drawCircle
{
//1.获得图形上下文
CGContextRef
//2.拼接图形
//画圆
CGContextAddEllipseInRect(ctx, 50 , 50 , 100 , 100 ));
//设置宽度
CGContextSetLineWidth(ctx, 10 );
//设置颜色
[[UIColor
//3.渲染到View
CGContextStrokePath(ctx);
}
</code>
|
假如想创建一个完整的圆圈,那么开始弧度就是0 结束弧度是2pi
最后,函数执行完后,current point就被重置为(x,y).还有一点要注意的是,假如当前path已经存在一个subpath,
那么这个函数执行的另外一个效果是会有一条直线,从current point到弧的起点。
文字绘制和图片绘制(pattern)
<h4 id="绘制文字和图片不要使用<a href=" http:="" www.2cto.com="" kf="" ware="" c="" "="" target="_blank" class="keylink" style="color: rgb(51, 51, 51); font-family: 宋体; font-size: 14px;">c语言函数原因如下">绘制文字和图片不要使用C语言函数。原因如下:Quarz2D
绘图坐标系和 UIKit 坐标系不一致,导致使用 C 语言函数绘文字和图片就会出现文字和图片颠倒的现象,需要通过写代码调整,要利用到数学中矩阵的知识。 使用 C 语言函数绘制文字和图片代码复杂且函数不好理解。非常麻烦。
图形上下文(Graphics Context)
简介
图形上下文(Graphics Context):是一个CGContextRef类型的数据
图形上行下文的作用
保存绘图信息、绘图状态 决定绘制的输出目标(绘制到什么地方去?)
(输出目标可以是PDF文件、Bitmap或者显示器的窗口上)
相同的一套绘图序列,指定不同的Graphics Context,就可将相同的图像绘制到不同的目标上
自定义View
如何利用Quartz2D绘制东西到view上?
首先,得有图形上下文,因为它能保存绘图信息,并且决定着绘制到什么地方去 其次,那个图形上下文必须跟view相关联,才能将内容绘制到view上面
自定义view的步骤
新建一个类,继承自UIView 实现- (void)drawRect:(CGRect)rect方法,然后在这个方法中 取得跟当前view相关联的图形上下文 绘制相应的图形内容 利用图形上下文将绘制的所有内容渲染显示到view上面
drawRect:
为什么要实现drawRect:方法才能绘图到view上?
因为在drawRect:方法中才能取得跟view相关联的图形上下文
drawRect:方法在什么时候被调用?
当view第一次显示到屏幕上时(被加到UIWindow上显示出来)
调用view的setNeedsDisplay或者setNeedsDisplayInRect:时
drawRect:中取得的上下文
在drawRect:方法中取得上下文后,就可以绘制东西到view上
View内部有个layer(图层)属性,drawRect:方法中取得的是一个Layer Graphics Context,因此,绘制的东西其实是绘制到view的layer上去了
View之所以能显示东西,完全是因为它内部的layer
绘图顺序
常用拼接路径函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<code class = "hljs"
"" >
新建一个起点
void
添加新的线段到某个点
void
添加一个矩形
void
添加一个椭圆
void
添加一个圆弧
void
CGFloat int
|
常用绘制路径函数
1
2
3
4
5
6
7
8
9
10
11
|
<code class = "hljs"
"" >Mode参数决定绘制的模式
void
绘制空心路径
void
绘制实心路径
void
提示:一般以CGContextDraw、CGContextStroke、CGContextFill开头的函数,都是用来绘制路径的
</code>
|
图形上下文栈的操作
1
2
3
4
5
|
<code class = "hljs"
"" >将当前的上下文copy一份,保存到栈顶(那个栈叫做”图形上下文栈”)
void
将栈顶的上下文出栈,替换掉当前的上下文
void
|
矩阵操作
利用矩阵操作,能让绘制到上下文中的所有路径一起发生变化
缩放void CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy)
旋转void CGContextRotateCTM(CGContextRef c, CGFloat angle)
平移void CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)
Quartz2D的内存管理
使用含有“Create”或“Copy”的函数创建的对象,使用完后必须释放,否则将导致内存泄露
使用不含有“Create”或“Copy”的函数获取的对象,则不需要释放
如果retain了一个对象,不再使用时,需要将其release掉
可以使用Quartz 2D的函数来指定retain和release一个对象。例如,如果创建了一个CGColorSpace对象,则使用函数CGColorSpaceRetain和CGColorSpaceRelease来retain和release对象。
也可以使用Core Foundation的CFRetain和CFRelease。注意不能传递NULL值给这些函数
常用示例
图片水印
水印:在图片上加的防止他人盗图的半透明logo、文字、图标
水印的作用
告诉你这个图片从哪来的
主要是一些网站为了版权问题、广告而添加的
有时候,在手机客户端app中也需要用到水印技术
比如,用户拍完照片后,可以在照片上打个水印,标识这个图片是属于哪个用户的
实现方式:利用Quartz2D,将水印(文字、LOGO)画到图片的右下角
核心代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<code class = "hljs"
"" ># import
@implementation
+(instancetype)waterImageWithBg:(NSString
{
UIImage @scene ];
//1.创建一个基于位图的上下文(开启一个基于位图的上下文)
//size:
//opaque
//scale
//这段代码过后就相当于创建一个新的bitmap,也就是新的UImage对象
UIGraphicsBeginImageContextWithOptions(bgImage.size, 0.0 );
//1.画背景
[bgImage 0 , 0 ,
//3.画右下角的水印
UIImage @logo ];
CGFloat 5 ;
CGFloat 0.5 ;
CGFloat
CGFloat
CGFloat
CGFloat
[waterImage
//4.从上下文取得制作完毕的UIImage对象
UIImage
//5.结束上下文
UIGraphicsEndImageContext();
return
}
@end
</code>
|
可以将图片导出为png图片
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<code class = "hljs"
"" > //6.显示到View
self.iconView.image
//7.将image压缩为PNG格式的二进制数据
NSData
//8.写入文件
NSString @new .png];
[data
//
</code>
|
图片裁剪
将普通的图片裁剪为圆形
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<code class = "hljs"
"" > //1.获得图片
UIImage @abc ];
//2.开始图片上下文
UIGraphicsBeginImageContext(image.size);
//画圆
//这段代码获得的上下文就是上一段代码开始的上下文
CGContextRef
CGContextAddEllipseInRect(ctx, 0 , 0 ,
CGContextClip(ctx);
//3.绘制图片
[image
//4.获得图片
UIImage
self.iconView.image
//5.关闭上下文
UIGraphicsEndImageContext();</code>
|
截屏
截取屏幕上的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<code class = "hljs"
"" >+(instancetype)catchImageWithView:(UIView
{
//开启图形上下文
UIGraphicsBeginImageContext(view.frame.size);
//将控制器中上下文的内容渲染到View中
[view.layer
//从图形上下文获得图片
UIImage
//关闭上下文
UIGraphicsEndImageContext();
return
}</code>
|