什么是Quartz 2D
1>Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac OS X系统(跨平台,纯C语言的),包含在Core Graphics框架中.
2> Quartz 2D的API是纯C语言的.数据类型和函数基本都是以CG作为前缀.如: CGContextRef, CGPathRef, CGContextStrokePath……
Quartz 2D能完成什么工作?
l1>绘制图形:线条,三角形,矩形,圆,弧,等….
l2>绘制文字.
l3>绘制生成图片(图像).
l4>读取\生成PDF.
l5>截图\裁剪图片.
l6>自定义UI控件,如环形下载进度条等.
Quartz 2D绘图主要步骤:
l1>获取“图形上下文”.
l2>向“图形上下文”中添加“路径”.
l3>渲染.把图形上下文中的图形绘制到对应的设备上.
关于图形上下文CGContextRef中主要包含的信息:
l1>绘图路径(各种各样的图形).
l2>绘制状态(颜色,线宽,样式,旋转,缩放,平移,图片裁剪区域等).
l3>输出目标(绘制到什么地方去?UIView,图片, pdf,打印机等).
使用Quartz 2D绘图:
l1>绘图路径(各种各样的图形).
l2>绘制状态(颜色,线宽,样式,旋转,缩放,平移,图片裁剪区域等).
l3>输出目标(绘制到什么地方去? UIView,图片, pdf,打印机等).
使用方式一直接调用Quartz2D的API进行绘图
l1>代码量稍大,功能全面.
l2>步骤如下.
步骤一获取绘图上下文
步骤二把图形绘制到绘图上下文中
步骤三把绘图上下文上的图形渲染到对应的设备上
使用方式二调用UIKit框架封装好的API进行绘图
l1>代码相对简单,只对部分Quartz2D的API做了封装.比如:画图片,文字到控件上.
l2>对于没有封装的功能只能调用Quartz2D原生的API
DrawRect:方法介绍
l1.为什么向UIView上绘图,代码必须写到drawRect:方法中?
原因:因为只有在view的drawRect:方法中,才能正确的获取这个view的layer的图形上下文。
l2.drawRect:方法一定不要自己手动去调用。系统会自动在该调用的时候去调用这个方法。
请问:为什么不能手动去调用这个方法?
1>因为系统在调用drawRect:方法之前,会先创建一个和当前view相关的layer的图形上下文。这样的话,在drawRect:这个方法中就可以正确的获取相应的图形上下文,然后就可以进行绘图了。
2>如果手动去调用drawRect:方法,那么在调用drawRect:方法的时候,无法保证和当前view相关的layer的图形上下文已经创建,所以在drawRect:这个方法中就可能无法正确的获取相应的图形上下文,如果没有图形上下文,那么也就无法进行绘图。
l3.如果必须需要重绘的话,怎么办?
解答:如果必须要进行一次重新绘制,那么也不要直接调用drawRect:方法,而是去调用setNeedsDisplay或者setNeedsDisplayInRect:。这两个方法内部会先创建一个图形上下文对象,然后调用drawRect:方法。
l4.drawRect:方法是什么时候调用的?调用几次?
1>这个方法只在第一次显示view的时候调用一次
2>如果后续需要重新刷新这个view的显示,那么需要调用setNeedsDisplay或者setNeedsDisplayInRect:
3>或者是当前view进行重新绘制的时候就会调用drawRect:方法
l5.drawRect:方法中的参数rect指的是什么?
解答:当前绘图view的bounds。
l6.补充和注意点:
1> UIView内部有个layer(图层)属性,drawRect:方法中取得的是一个Layer Graphics Context,因此,绘制的东西其实是绘制到view的layer上去了.
2> UIView之所以能显示东西,完全是因为它内部的layer.
l7.UIView主要的两个功能是什么?
1>显示,为什么UIView可以显示内容,原因是UIView内部有一个layer,也就是说我们实际上向UIView中绘制的所有内容,其实最终都是画在了layer上.
2>监听事件.
案例一Quartz2D简单演练
展示效果:
请问:实现的步骤是什么?
第一步,在控制器的界面中拖入一个UIView控件,并将类型更改为自定义的类型,重写drawRect:方法进行绘图,此时绘制的图形会被渲染到控件的layer图层上.
第二步,绘制线条和三角形,使用Quartz 2D原生API来进行绘图.请问:有哪3个步骤?.
1>获得图形上下文
2>拼接路径
3>渲染
第三步,使用UIKit框架封装好的UIBezierPath对象来进行绘制图形.请问:有哪几个步骤?.
1>获得图形上下文
2>创建一个UIBezierPath对象(路径对象)
3>向UIBezierPath对象中添加若干个路径
4>把UIBezierPath添加到对应的图形上下文中
5>渲染
第四步,绘制矩形框.
//代码实现使用Quartz2D原生API来进行绘图
------------------------------HMDrawingView.m------------------------------
//
Only override drawRect: if you perform custom drawing.An empty implementation
adversely affects performance during animation.
//仅仅只应该在自定义绘图的时候重写drawRect:该方法.如果仅仅重写该方法,而不执行任何代码,那么在执行动画期间会产生一些不利的影响.
```
- (void)drawRect:(CGRect)rect {
// 1.获取图形上下文
CGContextRefctx =UIGraphicsGetCurrentContext();
/**********路径信息**********/
// 2.向图形上下文中添加路径-绘制一个三角形
// 2.1移动到一个起始点
CGContextMoveToPoint(ctx,50,50);
// 2.2添加一条线到某个点
CGContextAddLineToPoint(ctx,150,50);
// 2.3再添加一条线段
CGContextAddLineToPoint(ctx,50,200);
// 2.4再添加一条线段
//CGContextAddLineToPoint(ctx, 50, 50);
// 2.5关闭路径
CGContextClosePath(ctx);
//在添加一个新的线段
// 2.6移动到一个新的起点-绘制一条线
CGContextMoveToPoint(ctx,50,260);
// 2.7添加一条线段
CGContextAddLineToPoint(ctx,260,260);
/**********状态信息**********/
//设置线条的状态
CGContextSetLineWidth(ctx,20);
//设置线头样式
CGContextSetLineCap(ctx,kCGLineCapRound);
//线段连接处的样式
CGContextSetLineJoin(ctx,kCGLineJoinRound);
//设置线条的颜色
[[UIColorredColor]setStroke];//空心
[[UIColoryellowColor]setFill];//实心
//设置stroke & fill颜色
[[UIColorblueColor]set];
// 3.渲染
CGContextStrokePath(ctx);//空心渲染
CGContextFillPath(ctx);//实心渲染
}
```
//代码实现使用UIKit框架封装好的UIBezierPath对象来进行绘制图形
------------------------------HMDrawingView.m------------------------------
```
- (void)drawRect:(CGRect)rect {
// 1.获取图形上下文
CGContextRefctx =UIGraphicsGetCurrentContext();
// 2.创建一个UIBezierPath对象(路径对象)
UIBezierPath*path = [UIBezierPathbezierPath];
// 3.向UIBezierPath对象中添加若干个路径
[pathmoveToPoint:CGPointMake(50,50)];
[pathaddLineToPoint:CGPointMake(150,50)];
[pathaddLineToPoint:CGPointMake(50,150)];
[pathclosePath];
// 4.把UIBezierPath添加到对应的图形上下文中
CGContextAddPath(ctx, path.CGPath);
// 5.渲染
CGContextStrokePath(ctx);
}
//步骤四绘制“矩形框”使用Quartz 2D原生API来进行绘图
- (void)drawRect:(CGRect)rect {
// 1.获取图形上下文
CGContextRefctx =UIGraphicsGetCurrentContext();
// 2.绘制矩形框
CGContextAddRect(ctx,CGRectMake(50,50,100,100));
// 3.渲染
CGContextStrokePath(ctx);
}
//步骤四使用UIKit框架封装好的UIBezierPath对象来进行绘制图形
- (void)drawRect:(CGRect)rect {
// 1.获取图形上下文
CGContextRefctx =UIGraphicsGetCurrentContext();
// 2.创建路径对象
UIBezierPath*path = [UIBezierPathbezierPathWithRect:CGRectMake(50,50,100,100)];
// 3.把路径添加到上下文中
CGContextAddPath(ctx, path.CGPath);
// 4.渲染
CGContextStrokePath(ctx);
}
```
//其它演练–核心代码
//绘制圆角矩形框
UIBezierPath*path =
[UIBezierPathbezierPathWithRoundedRect:CGRectMake(50,50,150,150)cornerRadius:20];//如果这里的圆角半径写成宽度高度的一半,那么就是一个圆
//绘制一个圆形
UIBezierPath*path =
[UIBezierPathbezierPathWithOvalInRect:CGRectMake(50,50,150,150)];
//绘制扇形
1> center :圆心
2> redius :半径
3> startAngle :起始角度
4> endAngle :结束角度
5> clockwise : YES ->顺时针旋转NO ->逆时针旋转
UIBezierPath*path =
[UIBezierPathbezierPathWithArcCenter:CGPointMake(150,150)radius:100startAngle:0endAngle:M_PIclockwise:YES];
Even-Odd
rule :奇偶填充规则
当一个点被覆盖过奇数次则“填充”,偶数次则“不填充”.
```
//代码实现
- (void)drawRect:(CGRect)rect {
// 1.获取图形上下文
CGContextRefctx =UIGraphicsGetCurrentContext();
// 2.绘制路径
UIBezierPath*path1 = [UIBezierPathbezierPathWithRect:CGRectMake(250,30,20,200)];
UIBezierPath*path2 = [UIBezierPathbezierPathWithArcCenter:CGPointMake(200,150)radius:80startAngle:0endAngle:M_PI*2clockwise:YES];
UIBezierPath*path3 = [UIBezierPathbezierPathWithRect:CGRectMake(100,100,200,100)];
// 3.添加路径
CGContextAddPath(ctx, path1.CGPath);
CGContextAddPath(ctx, path2.CGPath);
CGContextAddPath(ctx, path3.CGPath);
// 4.渲染
//说明:被覆盖过奇数次数的点填充,被覆盖过偶数次的点不填充
CGContextDrawPath(ctx,kCGPathEOFill);
}
```
nonzero
winding number rule :非零绕数规则
当一个点被从左到右覆盖过标记为1,从右到左覆盖过标记为-1,当标记为0的时候不填充,其它则填充.简单总结,这个规则与方向有关,与次数无关.
//代码实现
```
- (void)drawRect:(CGRect)rect
{
// 1.获取图形上下文
CGContextRefctx =UIGraphicsGetCurrentContext();
// 2.绘制路径
UIBezierPath*path1 = [UIBezierPathbezierPathWithArcCenter:CGPointMake(150,150)radius:100startAngle:0endAngle:M_PI*2clockwise:YES];
UIBezierPath*path2 = [UIBezierPathbezierPathWithArcCenter:CGPointMake(150,150)radius:50startAngle:0endAngle:M_PI*2clockwise:NO];
// 3.添加路径
CGContextAddPath(ctx,
path1.CGPath);
CGContextAddPath(ctx, path2.CGPath);
// 4.渲染
CGContextDrawPath(ctx,kCGPathFill);
}
```