?
简介
Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统
Quartz 2D能完成的工作
? ? ? ?绘制图形 : 线条\三角形\矩形\圆\弧等
? ? ? ?绘制文字
? ? ? ?绘制\生成图片(图像)
? ? ? ?读取\生成PDF
? ? ? ?截图\裁剪图片
? ? ? ?自定义UI控件
使用Quartz 2D绘制图形需要绘制在UIView上,而且要自定义的view。
自定义view的步骤
? ? ? ? 1、新建一个类,继承自UIView
? ? ? ??2、实现- (void)drawRect:(CGRect)rect方法,然后在这个方法中
? ? ? ??3、取得跟当前view相关联的图形上下文
? ? ? ??4、绘制相应的图形内容
?? ? ? ?5、利用图形上下文将绘制的所有内容渲染显示到view上面
几种简单的绘图方式
? ? #pragma mark - 最原始的绘图方式1
? ? - (void)draw2 {
? ? ? ? // Drawing code
?? ? ? ?
? ? ? ? //获得图形上下文
? ? ? ? CGContextRef con = UIGraphicsGetCurrentContext();
? ? ? ? // 创建路径
? ? ? ? CGMutablePathRef path = CGPathCreateMutable();
? ? ? ? // 绘制一条线
? ? ? ? //? ? CGPathMoveToPoint(path, NULL, 50, 50);
? ? ? ? //? ? CGPathAddLineToPoint(path, NULL, 200, 200);
? ? ? ? // 绘制矩形
? ? ? ? //? ? CGPathAddRect(path, NULL, CGRectMake(60, 60, 100, 100));
? ? ? ? //? ? CGPathAddEllipseInRect(path, NULL, CGRectMake(60, 60, 100, 100));
? ? ? ? // 圆角矩形
? ? ? ? //? ? CGPathAddRoundedRect(path, NULL, CGRectMake(60, 60, 100, 100), 5, 5);
? ? ? ? // 弧线
? ? ? ? CGPathAddArc(path, NULL, 100, 100,30, 0, M_PI, YES);
? ? ? ? // 添加路径到上下文中
? ? ? ? CGContextAddPath(con, path);
? ? ? ? // 显示到view中
? ? ? ? CGContextStrokePath(con);
? ? }
绘图方式2
? ? #pragma mark - 绘图方式2
? ? - (void)draw1 {
? ? ? ? // Drawing code
? ? ? ? //获得图形上下文
? ? ? ? CGContextRef con = UIGraphicsGetCurrentContext();
?? ? ? ?
? ? ? ? // 绘制路径
? ? ? ? // 绘制直线
? ? ? ? //? ? CGContextMoveToPoint(con, 0, 0);
? ? ? ? //? ? CGContextAddLineToPoint(con, 100, 100);
? ? ? ? //? ? CGContextAddLineToPoint(con, 50, 100);
? ? ? ? //CGContextMoveToPoint(con, 50, 50);
? ? ? ? //
? ? ? ? // 绘制圆
? ? ? ? //? ? CGContextAddEllipseInRect(con, CGRectMake(60, 60, 100, 100));
? ? ? ? // 绘制椭圆
? ? ? ? //? ? CGContextAddEllipseInRect(con, CGRectMake(60, 60, 150, 100));
? ? ? ? // 绘制矩形
? ? ? ? //? ? CGContextAddRect(con, CGRectMake(60, 60, 150, 100));
? ? ? ? // 绘制
? ? ? ? CGContextAddArc(con, 0, 0, 50, M_PI, M_PI_2, YES);
? ? ? ? // 显示到view中
? ? ? ? CGContextStrokePath(con);
绘图方式3
? ? #pragma mark - 绘图方式3-贝瑟尔路径绘图
? ? // 贝瑟尔路径绘图
? ? - (void)draw3 {
? ? ? ? // Drawing code
? ? ? ? // UIKit已经封装了一些绘图的功能
? ? ? ? // 贝瑟尔路径
? ? ? ? UIBezierPath *path = [UIBezierPathbezierPath];
?? ? ? ?
? ? ? ? // 绘制路径
? ? ? ? //? ? [path moveToPoint:CGPointMake(100, 100)];
? ? ? ? //? ? [path addLineToPoint:CGPointMake(200, 200)];
? ? ? ? // 圆弧
? ? ? ? [path addArcWithCenter:CGPointMake(100, 100) radius:50startAngle:0endAngle:M_PIclockwise:YES];// 顺时针绘制一个弧线
? ? ? ? [path addLineToPoint:CGPointMake(100, 100)];
?? ? ? ?
? ? ? ? [[UIColorredColor] setStroke]; // 设置线条颜色
? ? ? ? //
? ? ? ? path.lineJoinStyle = kCGLineJoinRound; //
? ? ? ? path.lineWidth = 2; // 宽度
? ? ? ? path.lineCapStyle = kCGLineCapRound; // 样式
?? ? ? ?
? ? ? ? [path fill];
? ? ? ? // 显示
? ? ? ? [path stroke];
? ? }
绘图状态的设置
? ? #pragma mark - 设置线条状态在渲染之前
? ? - (void)draw4 {
? ? ? ? // Drawing code
? ? ? ? // 获得图形上下文
? ? ? ? CGContextRef ct = UIGraphicsGetCurrentContext();
? ? ? ? // 绘制路径
? ? ? ? CGContextMoveToPoint(ct, 100, 100);
?? ? ? ?
? ? ? ? CGContextAddLineToPoint(ct, 200, 200);
?? ? ? ?
? ? ? ? CGContextAddLineToPoint(ct, 100, 300);
?? ? ? ?
? ? ? ? // 设置绘图状态,一定要在渲染之前设置,并且一经设置,状态会一直持续下去,除非再次改变。
? ? ? ? CGContextSetLineWidth(ct, 5);
? ? ? ? [[UIColorredColor] setStroke];
? ? ? ? CGContextSetLineJoin(ct, kCGLineJoinRound);
? ? ? ? CGContextSetLineCap(ct, kCGLineCapRound);
? ? ? ? // 渲染
? ? ? ? CGContextStrokePath(ct);
? ? }
绘制包含多个状态的图形?
? ? - (void)drawRect:(CGRect)rect {
? ? ? ? // Drawing code
? ? ? ? // 绘制多个状态不同的线
? ? ? ? // 获得图形上下文
? ? ? ? UIBezierPath *path = [UIBezierPath bezierPath];
? ? ? ? // 绘制路径
? ? ? ? [path moveToPoint:CGPointMake(100, 100)];
? ? ? ? [path addLineToPoint:CGPointMake(200, 200)];
? ? ? ? // 设置绘图状态,一定要在渲染之前设置,并且一经设置,状态会一直持续下去,除非再次改变。
? ? ? ? [[UIColor redColor] setStroke];
? ? ? ? // 渲染
? ? ? ? [path stroke];
?? ? ? ?
? ? ? ? // 获得图形上下文
? ? ? ? UIBezierPath *path1 = [UIBezierPath bezierPath];
? ? ? ? // 绘制路径
? ? ? ? [path1 moveToPoint:CGPointMake(200 , 200)];
? ? ? ? [path1 addLineToPoint:CGPointMake(100, 150)];
? ? ? ? // 设置绘图状态,一定要在渲染之前设置,并且一经设置,状态会一直持续下去,除非再次改变。
? ? ? ? [[UIColor blueColor] setStroke];
? ? ? ? // 渲染
? ? ? ? [path1 stroke];
? ? }
绘制饼状图
首先花圆弧,然后连接圆心,最后填充位一个扇形
?
? ? // 饼状图2
? ? - (void)drawRect:(CGRect)rect{
? ? ? ? NSArray *arr = [self randomArray]; // 随机地返回一个数组,数组元素和为100
? ? ? ? // 获取半径和圆心
? ? ? ? CGFloat radius = self.frame.size.height/2 - 2;
? ? ? ? CGPoint center = CGPointMake(radius, radius);
? ? ? ? // 绘制角度
? ? ? ? CGFloat startAngle = 0;
? ? ? ? CGFloat endAngle = 0;
?? ? ? ?
? ? ? ? // 绘制图形
? ? ? ? for (int i = 0 ; i < arr.count; i ++) {
?? ? ? ? ? ?
? ? ? ? ? ? // 计算角度
? ? ? ? ? ? endAngle = startAngle + [arr[i] floatValue] / 100.0 * M_PI * 2;
? ? ? ? ? ? // 绘制图形
? ? ? ? ? ? UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
? ? ? ? ? ? [path addLineToPoint:center];
?? ? ? ? ? ?
? ? ? ? ? ? startAngle = endAngle;
? ? ? ? ? ? // 设置颜色
? ? ? ? ? ? [[self randomColor] set];
? ? ? ? ? ? // 填充,并且把终点和起始点连接起来
? ? ? ? ? ? [path fill];
? ? ? ? }
? ? }
随机返回数组,且元素和为100?
? ? // 返回随机数组,且数组元素和为100
? ? - (NSArray *)randomArray
? ? {
? ? ? ? NSMutableArray *arr = [NSMutableArrayarray];
? ? ? ? int total = 100;
?? ? ? ?
? ? ? ? int temp = 0;
? ? ? ? for (int i = 0 ; i < arc4random_uniform(10) + 1;i ++) {
? ? ? ? ? ? // 100 1~100
? ? ? ? ? ? temp = arc4random_uniform(total) + 1;
? ? ? ? ? ? // 随机出来的临时值等于总值,直接退出循环,因为已经把总数分配完毕,没必要在分配。
? ? ? ? ? ? [arr addObject:@(temp)];
?? ? ? ? ? ? // 解决方式:当随机出来的数等于总数直接退出循环。
? ? ? ? ? ? if (temp == total) {
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? ? ? total -= temp;
?? ? ? ? ? ?
? ? ? ? }
? ? ? ? // 如果总数大于0就添加到数组中
? ? ? ? if (total ) {
? ? ? ? ? ? [arr addObject:@(total)];
? ? ? ? }
? ? ? ? return? arr;
? ? }
返回随机颜色
? ??// 返回随机的颜色
? ? - (UIColor *)randomColor
? ? {
? ? ? ? // iOS:RGB返回是0~1
? ? ? ? CGFloat r = arc4random_uniform(256) / 255.0;
? ? ? ? CGFloat g = arc4random_uniform(256) / 255.0;
? ? ? ? CGFloat b = arc4random_uniform(256) / 255.0;
? ? ? ? return [UIColorcolorWithRed:r green:g blue:b alpha:1];
? ? }
绘制柱状图
计算方柱个数,平分宽度,高度按占视图比例计算。
?
? ? // 柱状图
? ? - (void)drawRect:(CGRect)rect {
? ? ? ? // 随机地返回一个数组,数组元素和为100
? ? ? ? NSArray *arr = [self randomArray];
? ? ? ? // 起始点和高度
? ? ? ? CGFloat x = 0;
? ? ? ? CGFloat y = 0;
? ? ? ? CGFloat w = 0;
? ? ? ? CGFloat h = 0;
?? ? ? ?
? ? ? ? NSInteger count = arr.count;
? ? ? ? // 宽度
? ? ? ? w = rect.size.width / (2*count - 1);
?? ? ? ?
? ? ? ? for (int i = 0 ; i < arr.count; i ++) {
? ? ? ? ? ? // x坐标
? ? ? ? ? ? x = 2*i * w;
? ? ? ? ? ? // 高度
? ? ? ? ? ? h = [arr[i] floatValue] / 100.0 * rect.size.height;
? ? ? ? ? ? // y坐标
? ? ? ? ? ? y = rect.size.height - h;
? ? ? ? ? ? UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(x, y, w, h)];
? ? ? ? ? ? [[self randomColor] set];
? ? ? ? ? ? [path fill];
? ? ? ? }
? ? }
文本显示
?
? ? // 文本显示
? ? - (void)drawRect:(CGRect)rect
? ? {
? ? ? ? NSString *str = @"哈尽快回家的客户发动机可舒服哈的尽快发货阿红的健康法哈德减肥哈第三方阿姐回复就爱的客户房间卡地方哈就等哈接电话发掘";
? ? ? ? // 这个方法不会自动换行
? ? //? ? [str drawAtPoint:CGPointZero withAttributes:nil];
? ? ? ? // 自动换行
? ? ? ? [str drawInRect:rect withAttributes:nil];
? ? }
富文本显示
? ? // 富文本:带有状态的文本
? ? - (void)drawRect:(CGRect)rect
? ? {
? ? ? ? NSString *str = @"哈尽快回家的客户发动机可舒服哈的尽快发货阿红的健康法哈德减肥哈第三方阿姐回复就爱的客户房间卡地方哈就等哈接电话发掘";
?? ? ? ?
? ? ? ? NSMutableDictionary *dict = [NSMutableDictionarydictionary];
?? ? ? ?
? ? ? ? // 属性的设置可以在UIkit框架的头文件里找到解释
? ? ? ? // 字体颜色
? ? ? ? dict[NSForegroundColorAttributeName] = [UIColorredColor];
? ? ? ? // 字体大小
? ? ? ? dict[NSFontAttributeName] = [UIFontsystemFontOfSize:30];
? ? ? ? // 字体粗细
? ? ? ? dict[NSStrokeWidthAttributeName] = @5;
? ? ? ? // 颜色
? ? ? ? dict[NSStrokeColorAttributeName] = [UIColorgreenColor];
? ? ? ? // 阴影
? ? ? ? NSShadow *sha = [[NSShadow alloc] init];
? ? ? ? sha.shadowOffset = CGSizeMake(5, 5);
? ? ? ? sha.shadowBlurRadius = 10;
? ? ? ? sha.shadowColor = [UIColor yellowColor];
? ? ? ? dict[NSShadowAttributeName] = sha;
? ? ? ? // 绘制到视图
? ? ? ? [str drawInRect:rect withAttributes:dict];
? ? }
绘制图片到视图
drawAtPoint
?
drawInRect
drawAsPatternInrect
? ?
裁剪
?
? ? // 绘制图形
? ? - (void)drawRect:(CGRect)rect
? ? {
? ? ? ? // 超出裁剪区域的内容全部裁剪掉
? ? ? ? // 注意:裁剪必须放在绘制之前
?? ? ? // UIRectClip(CGRectMake(0, 0, 100, 100));
?? ? ? ?
? ? ? ? UIImage *image = [UIImage imageNamed:@"010"];
? ? ? ? // 默认按照图片比例显示
? ? //? ? [image drawAtPoint:CGPointZero];
? ? ? ? // 将整个图片显示到rect中,拉伸或者缩小
? ? ? ? [image drawInRect:rect];
? ? ? ? // 默认填充显示
? ? //? ? [image drawAsPatternInRect:rect];
? ? }
图形上下文状态
保存某个状态到栈顶,用于之后恢复。
? ? // 图形上下文3 UIBezierPath:使用[path stroke];时上下文状态有UIBezierPath自身决定
? ? - (void)drawRect:(CGRect)rect
? ? {
? ? ? ? //保存上下文状态,如果使用这种方法保存上下文状态的话,需要设置以CGContext开头的那些函数设置状态,
? ? ? ? // 获取图形上下文
? ? ? ? CGContextRef ctx = UIGraphicsGetCurrentContext();
? ? ? ? // 绘制第一条线
? ? ? ? // 贝塞尔路线
? ? ? ? UIBezierPath *path? = [UIBezierPathbezierPath];
? ? ? ? // 绘制路径
? ? ? ? [path moveToPoint:CGPointMake(55, 55)];
? ? ? ? [path addLineToPoint:CGPointMake(99, 90)];
? ? ? ? // 添加路径到上下文
? ? ? ? //将c路径转换成oc对象:CGPath
? ? ? ? CGContextAddPath(ctx, path.CGPath);
? ? ? ? // 保存上下文状态
? ? ? ? CGContextSaveGState(ctx);
? ? ? ? CGContextSetLineWidth(ctx, 5);
? ? ? ? [[UIColorredColor] setStroke];
? ? ? ? // 渲染上下文
? ? //? ? [path stroke];
? ? ? ? CGContextStrokePath(ctx);
?? ? ? ?
? ? ? ? // 绘制第二条线
? ? ? ? path? = [UIBezierPath bezierPath];
? ? ? ? // 绘制路径
? ? ? ? [path moveToPoint:CGPointMake(100, 10)];
? ? ? ? [path addLineToPoint:CGPointMake(100, 80)];
? ? ? ? // 恢复上下文状态
? ? ? ? CGContextRestoreGState(ctx);
? ? ? ? // 添加路径到上下文
? ? ? ? CGContextAddPath(ctx, path.CGPath);
? ? //? ? [[UIColor blueColor] setStroke];
? ? ? ? // 渲染
? ? //? ? [path stroke];
? ? ? ? CGContextStrokePath(ctx);
? ? }
绘图刷新-定时器
?如果在绘图的时候需要用到定时器,通常CADisplayLink
?NSTimer很少用于绘图,因为调度优先级比较低,并不会准时调用
? ??// 如果在绘图的时候需要用到定时器,通常CADisplayLink
? ? // NSTimer很少用于绘图,因为调度优先级比较低,并不会准时调用
? ? - (void)awakeFromNib
? ? {
? ? ? ? // 添加计时器,改变_smailY的值
? ? //? ? 比起NSTimer,CADisplayLink可以确保系统渲染每一帧的时候我们的方法都被调用,从而保证了动画的流畅性。
? ? ? ? // CADisplayLink:每次屏幕刷新的时候就会调用,屏幕一般一秒刷新60次
? ? ? ? CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(timeChange)];
? ? ? ? // 添加至运行主循环
? ? ? ? [link addToRunLoop:[NSRunLoop?mainRunLoop] forMode:NSDefaultRunLoopMode];
? ? }
? ? - (void)timeChange
? ? { ? ? ?
? ? ? ? // 注意:这个方法并不会马上调用drawRect,其实这个方法只是给当前控件添加刷新的标记,等下一次屏幕刷新的时候才会调用drawRect
? ? ? ? [self?setNeedsDisplay];
? ? }
矩阵操作
? ??// 上下文矩阵操作
? ? // 注意:矩阵操作必须要在添加路径之前
? ? -(void)drawRect:(CGRect)rect
? ? {
? ? ? ? // 获取图形山下文
? ? ? ? CGContextRef ctx1 = UIGraphicsGetCurrentContext();
? ? ? ? //? ? CGContextSaveGState(ctx1);
? ? ? ? // 绘制路径1
? ? //? ? CGContextMoveToPoint(ctx1, 50, 50);
? ? ? ? CGContextTranslateCTM(ctx1, 100, 0); // 添加路径之前进行矩阵操作
? ? ? ? CGContextScaleCTM(ctx1, 2, 2);
? ? ? ? CGContextRotateCTM(ctx1, M_PI_2);
? ? ? ? CGContextAddEllipseInRect(ctx1, CGRectMake(10, 10, 50, 90));
?? ? ? ?
? ? ? ? [[UIColorredColor] setStroke];
? ? ? ? CGContextSetLineWidth(ctx1, 5);
? ? ? ? CGContextSetLineJoin(ctx1, kCGLineJoinRound);
? ? ? ? // 渲染路径
? ? ? ? CGContextStrokePath(ctx1);
? ? }
?