转载自:http://www.jianshu.com/p/24e99ecd3b42
Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统
Quartz 2D能完成的工作:
- 绘制图形 : 线条/三角形/矩形/圆/弧等
- 绘制文字
- 绘制/生成图片(图像)
- 读取/生成PDF
- 截图/裁剪图片
- 自定义UI控件 (重要)
图形上下文
图形上下文(Graphics Context):是一个CGContextRef类型的数据
图形上下文的作用:
- 保存绘图信息、绘图状态
- 决定绘制的输出目标(绘制到什么地方去?)
(输出目标可以是PDF文件、Bitmap或者显示器的窗口上)
相同的一套绘图序列,指定不同的Graphics Context,就可将相同的图像绘制到不同的目标上
Quartz2D提供了以下几种类型的Graphics Context:
- Bitmap Graphics Context
- PDF Graphics Context
- Window Graphics Context
- Layer Graphics Context
- Printer Graphics Context
drawRect:方法
-
如何利用Quartz2D绘制东西到view上?
首先,得有图形上下文,因为它能保存绘图信息,并且决定着绘制到什么地方去
其次,那个图形上下文必须跟view相关联,才能将内容绘制到view上面
-
如何利用Quartz2D自定义view?(自定义UI控件)
1.新建一个类,继承自UIView
2.实现- (void)drawRect:(CGRect)rect方法,然后在这个方法中取得跟当前view相关联的图形上下文
3.绘制相应的图形内容
4.利用图形上下文将绘制的所有内容渲染显示到view上面
-
为什么要实现drawRect:方法才能绘图到view上?
因为在drawRect:方法中才能取得跟view相关联的图形上下文
-
drawRect:方法在什么时候被调用?
当view第一次显示到屏幕上时(被加到UIWindow上显示出来)
调用view的setNeedsDisplay(重绘)或者setNeedsDisplayInRect:时
注意:调用setNeedsDisplay方法并不会立马调用drawRect:方法,只是设了一个标志,当屏幕下一次刷新的时候才去调用drawRect:方法。(屏幕每秒刷新60次)
画直线
/**
* 在drawRect:方法中系统已经帮你创建好了一个跟view相关联的上下文(layer上下文),只需要获取就好了
* 作用:专门用来绘图
* 什么时候调用:当view显示的时候自动调用
* @param rect:当前view的bounds
*
*/
- (void)drawRect:(CGRect)rect {
//1.获取图形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//上下文的状态(线的粗细、颜色、链接样式等)
//设置线的粗细
CGContextSetLineWidth(ctx, 10);
//设置链接点的样式
/**
typedef CF_ENUM(int32_t, CGLineJoin) {
kCGLineJoinMiter,
kCGLineJoinRound,
kCGLineJoinBevel
};
*/
CGContextSetLineJoin(ctx, kCGLineJoinRound);
//设置线的顶角样式
/**
typedef CF_ENUM(int32_t, CGLineCap) {
kCGLineCapButt,
kCGLineCapRound,
kCGLineCapSquare
};
*/
CGContextSetLineCap(ctx, kCGLineCapRound);
//设置颜色(注意:这里设置颜色必须跟渲染方式一致,否则设置不上颜色)
// [[UIColor redColor]setFill]; //渲染方式为Fill
// [[UIColor redColor]setStroke]; //渲染方式为Stroke
[[UIColor redColor]set]; //两种渲染方式均可,推荐使用
//2. 绘制路径
UIBezierPath *path = [UIBezierPath bezierPath];
//2.1 设置起点
[path moveToPoint:CGPointMake(50, 250)];
//2.2 添加一根线到终点
[path addLineToPoint:CGPointMake(250, 50)];
//画第二条直线(新起点)
[path moveToPoint:CGPointMake(100, 250)];
[path addLineToPoint:CGPointMake(250, 100)];
//把上一条线的终点当做起点来画第二条线
[path addLineToPoint:CGPointMake(250, 250)];
//3.把绘制的内容添加到上下文中
// UIBezierPath:UIKit框架 ---> CGPathRef:CoreGraphics框架
CGContextAddPath(ctx, path.CGPath);
//4.把上下文的内容显示到view上(渲染到view的layer上)渲染的方式有两种Stroke(描边)、Fill(填充)
CGContextStrokePath(ctx);
}
画曲线
//画曲线 - (void)drawQuadCurve{ //1.获取图形上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); //2.绘制图形 UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(50, 250)]; //添加一条曲线 [path addQuadCurveToPoint:CGPointMake(250, 250) controlPoint:CGPointMake(50, 50)]; //3.把绘制的内容添加到上下文中 CGContextAddPath(ctx, path.CGPath); //4.把上下文的内容渲染到view上 CGContextStrokePath(ctx); }
![](http://img1.tuicool.com/BjIrqqV.jpg%21web)
图片来自苹果官方文档
画矩形
- (void)drawRect:(CGRect)rect { //1.获取图形上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); //设置颜色 [[UIColor redColor]set]; //2.绘制路径 //画矩形 // UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 100, 100)]; //画圆角矩形 UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 100, 100) cornerRadius:50]; //3.把路径添加到上下文 CGContextAddPath(ctx, path.CGPath); //4.把上下文渲染到view上 //描边 // CGContextStrokePath(ctx); //填充 CGContextFillPath(ctx); }
画椭圆
- (void)drawRect:(CGRect)rect { //画椭圆 UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 100, 50)]; //画矩形 // UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 100, 50)]; //画线 [path moveToPoint:CGPointMake(50, 250)]; [path addLineToPoint:CGPointMake(250, 250)]; //设置颜色 [[UIColor redColor]set]; //设置线条的粗细 [path setLineWidth:10]; //[path stroke] 底层: //1.获取图形上下文 -> 2.绘制路径 -> 3.把路径添加到上下文 -> 4.把上下文渲染到view上 [path stroke]; //填充 // [path fill]; }
画弧
- (void)drawRect:(CGRect)rect { //画弧 //ArcCenter:弧所在圆的圆心 //radius:弧所在圆的半径 //startAngle:起始角度 //endAngle:结束角度 //clockwise: YES:顺时针 NO:逆时针 //不能直接使用self.center :因为self.center坐标是相对于他的父控件 CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5); CGFloat radius = rect.size.width * 0.5 - 10; UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:M_PI_4 clockwise:YES]; [path stroke]; }
画扇形
- (void)drawRect:(CGRect)rect { //画弧 //ArcCenter:弧所在圆的圆心 //radius:弧所在圆的半径 //startAngle:起始角度 //endAngle:结束角度 //clockwise: YES:顺时针 NO:逆时针 //不能直接使用self.center :因为self.center坐标是相对于他的父控件 CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5); CGFloat radius = rect.size.width * 0.5 - 10; UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:M_PI_4 clockwise:YES]; //画扇形 //添加一根线到圆心 [path addLineToPoint:center]; //关闭路径:从路径终点添加一根线到路径的起点 [path closePath]; //填充之前,会自动关闭路径 // [path fill]; [path stroke]; }
画饼图
#import "PieView.h" @implementation PieView - (void)drawRect:(CGRect)rect { NSArray *dataArray = @[@15,@20,@5,@10,@50]; CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5); CGFloat redius = rect.size.width * 0.5 - 10; CGFloat startA = 0; CGFloat angle = 0; CGFloat endA = 0; for (NSNumber *num in dataArray) { startA = endA; angle = num.intValue / 100.0 * M_PI * 2; endA = startA + angle; UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:redius startAngle:startA endAngle:endA clockwise:YES]; //随机颜色 [[self randomColor]set]; //弧的终点向圆心画一条线 [path addLineToPoint:center]; //填充 [path fill]; } } //随机颜色 - (UIColor *)randomColor{ CGFloat r = arc4random_uniform(256) / 255.0; CGFloat g = arc4random_uniform(256) / 255.0; CGFloat b = arc4random_uniform(256) / 255.0; return [UIColor colorWithRed:r green:g blue:b alpha:1]; } @end
![](http://img1.tuicool.com/ENbyYjI.png%21web)
饼图
UIKit绘图
画文字
- (void)drawRect:(CGRect)rect {
// Drawing code
NSString *str = @"Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统";
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
//设置文字大小
dict[NSFontAttributeName] = [UIFont systemFontOfSize:20];
//设置文字颜色
dict[NSForegroundColorAttributeName] = [UIColor greenColor];
//设置描边宽度
dict[NSStrokeWidthAttributeName] = @2;
//设置描边颜色
dict[NSStrokeColorAttributeName] = [UIColor blueColor];
//设置阴影
NSShadow *shadow = [[NSShadow alloc] init];
//设置阴影的便宜量
shadow.shadowOffset = CGSizeMake(10, 10);
//设置阴影颜色
shadow.shadowColor = [UIColor greenColor];
//设置阴影模糊程序
shadow.shadowBlurRadius = 1;
dict[NSShadowAttributeName] = shadow;
/**
AtPoint:文字所画的位置
withAttributes:描述文字的属性.
*/
//不会自动换行
[str drawAtPoint:CGPointZero withAttributes:dict];
//会自动换行.
[str drawInRect:self.bounds withAttributes:dict];
}
画图片
- (void)drawRect:(CGRect)rect { // Drawing code //1.加载图片 UIImage *image = [UIImage imageNamed:@"agt"]; //绘制出来的图片,是保持原来图片大小 [image drawAtPoint:CGPointZero]; //把图片填充到这个rect当中. [image drawInRect:rect]; //添加裁剪区域 .把超区裁剪区域以外都裁剪掉 UIRectClip(CGRectMake(0, 0, 50, 50)); //平铺 [image drawAsPatternInRect:self.bounds]; //快速的画出一个矩形 [[UIColor blueColor] set]; UIRectFill(CGRectMake(10, 10, 100, 100)); }
上下文状态栈
- (void)drawRect:(CGRect)rect {
// Drawing code
//1.获取图形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2.描述路径
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10, 100)];
[path addLineToPoint:CGPointMake(150, 100)];
/*******保存当前上下文的状态到上下文状态栈*********/
CGContextSaveGState(ctx);
//修改状态
CGContextSetLineWidth(ctx, 10);
[[UIColor redColor]set];
//3.将路径添加到上下文
CGContextAddPath(ctx, path.CGPath);
//4.将上下文渲染到view上
CGContextStrokePath(ctx);
//2.描述路径
UIBezierPath *path2 = [UIBezierPath bezierPath];
[path2 moveToPoint:CGPointMake(100, 10)];
[path2 addLineToPoint:CGPointMake(100, 150)];
//修改状态
// CGContextSetLineWidth(ctx, 1);
// [[UIColor blackColor]set];
/*******从上下文状态栈中取出最上面的状态*********/
CGContextRestoreGState(ctx);
//3.将路径添加到上下文
CGContextAddPath(ctx, path2.CGPath);
//4.将上下文渲染到view上
CGContextStrokePath(ctx);
}
@end
![](http://img1.tuicool.com/mmaeii7.png%21web)
绘制不同的状态
图形上下文的矩阵操作
- (void)drawRect:(CGRect)rect { // Drawing code //1.获取图形上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); //2.绘制路径 UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 100, 50)]; //把路径添加到上下文中之前可以做一些矩阵操作 //平移 CGContextTranslateCTM(ctx, 100, 100); //旋转 CGContextRotateCTM(ctx, M_PI_4); //缩放 CGContextScaleCTM(ctx, 1.5, 1.5); //3.把路径添加到图形上下文中 CGContextAddPath(ctx, path.CGPath); //4.把上下文渲染到view上 CGContextFillPath(ctx); }
当然,在实际开发中我们不需要自己去画折线图、饼图、各种统计图... ...
一个很好的第三方库 Charts 是一个简单、面向对象、为设计者和开发者准备的图表绘制工具库