iOS——Quartz2D(二维图形绘制)

Quartz 2D属于Core Graphics(所以大多数相关方法的都是以CG开头),是iOS/Mac OSX 提供的在内核之上的强大的2D绘图引擎,并且这个绘图引擎是设备无关的。也就是说,不用关心设备的大小,设备的分辨率,只要利用Quartz 2D,这些设备相关的会自动处理。Quartz 2D能够提供的强大功能如下:

  • 透明层(transparency layers)
  • 阴影
  • 基于path的绘图(path-based drawing)
  • 离屏渲染(offscreen rendering)
  • 复杂的颜色处理(advanced color management)
  • 抗锯齿渲染(anti-aliased rendering)
  • PDF创建,展示,解析(这部分不在这个系列之中)
  • 配合Core Animation, OpenGL ES,UIKit完成复杂的功能

##1、Graphics Context

  • 概述: Core Graphics API所有的操作都在⼀个上下⽂中进行。所以在绘图之前需要获取该上下文并传入执行渲染的函数中。如果你正在渲染一副在内存中的图片,此时就需要传⼊图⽚所属的上下文。获得⼀个图形上下文是我们完成绘图任务的第一步,你可以将图形上下文理解为一块画布。如果你没有得到这块画布,那么你就无法完成任何绘图操作。

  • Quartz2D提供了以下几种类型的Graphics Context:

Bitmap Graphics Context
PDF Graphics Context
Window Graphics Context
Layer Graphics Context
Printer Graphics Context
  • 一个Graphics Context表⽰示一个绘制目标。它包含绘制系统用于完成绘制指令的绘制参数和设备相关信息

  • Graphics Context定义了基本的绘制属性,如颜色、裁减区域、线条宽度和样式信息、字体信息、混合模式等

  • 在iOS应用程序中,如果要在屏幕上进行绘制,需要创建⼀个UIView对象,并实现它的 drawRect:⽅法。视图的drawRect:⽅法在视图显示在屏幕上及它的内容需要更新时被调用

  • 在调⽤自定义的drawRect:后,视图对象自动配置绘图环境以便能⽴即执行绘图操作

  • 作为配置的⼀部分,视图对象将为当前的绘图环境创建⼀个Graphics Context。通过调⽤UIGraphicsGetCurrentContext()方法可以获取当前的Graphics Context

##2、Qudrtz 2D坐标系

坐标系统定义是被绘制到Page上的对象的位置及⼤小范围,我们在用户 空间坐标系统(user-space coordination system,简称用户空间)中指定图形的位置及⼤小。坐标值是用浮点数来定义的。

Quartz中默认的坐标系统是:原点(0, 0) 在左下角。沿着X轴从左到右坐标值逐渐增大;沿着Y轴从下到上坐标值逐渐增大

有⼀些技术在设置它们的graphics context时使用了不同于Quartz的默认坐标系统。最常⻅的⼀种修改的坐标系统是原点位于左上角,⽽沿着Y轴从上到下坐标值逐渐增⼤。例如:UIView中的UIGraphicsGetCurrentContext方法返回的图形上下⽂就是用的是这种坐标系

###2.1 UIKit坐标系

  • 原点(0,0)在屏幕的左上角,X轴向右正向延伸,Y轴向下正向延伸

  • iOS的像素分辨率会随设备的硬件而变化,iPhone4第⼀次引入了视⺴膜屏幕,像素分辨率为960 * 640,刚好是前⼀一代iPod和iPhone像素分辨率( 480 * 320)的两倍

  • 在绘图时,需要使用“点”的概念来思考问题,⽽不是像素。也就是说在点坐标系中绘图,不是硬件的像素坐标系

  • 虽然这些设备的像素分辨率不同,但用到的坐标系保持不变(以点为单位)。在iPhone4 上,⼀个点会用2像素宽度来绘制

提示:如果绘图的上下文,是使⽤UIGraphicsGetCurrentContext或者其他以UI开头的⽅法获取到的,在绘图时无需进行坐标转换

###2.2 坐标系的转换

  • CGContextRotateCTM(CGContextRef c, CGFloat angle)⽅法可以相对原点旋转上下文坐标系

  • CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)⽅法可以相对原点平移上下文坐标系

  • CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy)方法可以缩放上下⽂坐标系 注意: 转换坐标系前,使⽤CGContextSaveGState(CGContextRef c)保存当前上下文 状态坐标系转换后,使用CGContextRestoreGState(CGContextRef c)可以恢复之前保存的上下⽂状态

##3、绘图方法 Quartz 2D绘图流程:

  • 获取上下⽂
  • 保存上下文
  • 创建及设置路径
  • 将路径添加到上下⽂
  • 设置上下文状态(边框颜色,填充颜色,线条宽度,线段连接样式,线段⾸尾样式,虚线样式等)
  • 绘制路径
  • 释放路径
  • 恢复上下⽂

路径:

  • 路径定义了一个或多个形状,或是⼦路径。
  • 一个⼦子路径可由直线,曲线,或者同时由两者构成。
  • 它可以是开放的,也可以是闭合的。
  • 一个子路径可以是简单的形状,如线、圆、矩形、星形;
  • 也可以是复杂的形状,如山脉的轮廓或者是涂鸦。
  • 路径可以是开放的,也可以是封闭的;对于封闭路径可以空心的也可以是实⼼的

在iOS应用程序中,如果要使用 Core Graphics 在屏幕上进行绘制图像需要在如下方法中进行。

  • drawRect:方法 需要创建一个UIView对象,并实现它的drawRect:方法。视图的drawRect:方法在视图显示在屏幕上及它的内容需要更新时被调用,或者使用setNeedsDisplay手动调用。
// 1. 将自定义视图添加到视图上显示
- (void)viewDidLoad {
    [super viewDidLoad];

    DrawView *drawView = [[DrawView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:drawView];
}
// 2. 在自定义的DrawView 中绘图,当视图显示时就会调用下面的代码。
- (void)drawRect:(CGRect)rect
{

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextAddRect(ctx, CGRectMake(10, 20, 100, 100));
    CGContextSetFillColorWithColor(ctx, [UIColor grayColor].CGColor);
    CGContextDrawPath(ctx, kCGPathFill);
}
  • drawLayer: inContext:方法 这是CALayer的代理方法,需要设置图层的代理对象并使用setNeedsDisplay方法才能触发这个方法。
// 1.创建一个layer并设置代理为当前控制器
- (void)viewDidLoad {
    [super viewDidLoad]; 

    CALayer *dLayer = [CALayer layer];
    dLayer.frame = self.view.bounds;
    dLayer.delegate = self;
    [self.view.layer addSublayer:dLayer];  
    [dLayer setNeedsDisplay]; // 调用这个方法才能触发代理方法绘图
}
// 2. 在代理方法中绘图
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{

    // 绘制三角形
    CGContextSetLineWidth(ctx, 2);
    CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);
    CGContextSetStrokeColorWithColor(ctx, [UIColor whiteColor].CGColor);
    CGContextMoveToPoint(ctx, 0, 400);
    CGContextAddLineToPoint(ctx, 320, 400);
    CGContextAddLineToPoint(ctx, 160, 560);
    CGContextAddLineToPoint(ctx, 0, 400);
    CGContextFillPath(ctx);  // 填充
    CGContextStrokePath(ctx); // 描边
}

##4、Core Graphics上下文函数

绘图上下文相关函数

UIGraphicsGetCurrentContext(): 获取当前绘图上下文,绘图前的第一步,因为所有的绘图都是在上下文完成的,可以理解为获取当前绘图的“画布”。

CGContextSaveGState():保存上下文状态,这个函数的作用是将当前图形状态推入堆栈。之后,您对图形状态所做的修改会影响随后的描画操作,但不影响存储在堆栈中的拷贝。

CGContextRestoreGState(): 恢复上下文状态,通过这个函数把堆栈顶部的状态弹出,返回到之前的图形状态。和CGContextSaveGState()配对使用。

CGContextSaveGState()CGContextRestoreGState()使用举例:整个绘图都是红色,但是中间需要有个图是灰色,这种场景就可以使用这两个函数处理了。

  // 先设置图形的填充颜色为红色
  CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);
  // 将之前设置的状态入栈保存
  CGContextSaveGState(ctx); 
  CGContextAddRect(ctx, CGRectMake(10, 20, 100, 100));
  // 设置中间图形的填充色修改为灰色
  CGContextSetFillColorWithColor(ctx, [UIColor grayColor].CGColor);
  CGContextDrawPath(ctx, kCGPathFillStroke);
  // 恢复到保存前的绘图状态,那么后面的绘图就不是灰色了,而是原来的红色。
  CGContextRestoreGState(ctx);  

##5、使用Core Graphics绘图

  • 获取当前绘图上下文,相当于创建“画布”
    CGContextRef ctx = UIGraphicsGetCurrentContext();
  • 设置要绘制的图形
    //直线   
    CGContextMoveToPoint(ctx, 100, 250);
    CGContextAddLineToPoint(ctx, 150, 150);
    // 矩形
    CGContextAddRect(ctx, CGRectMake(10, 20, 100, 100));
    // 内切圆\椭圆
    CGContextAddEllipseInRect(ctx, CGRectMake(120, 20, 100, 100));
    // 三角形
    CGContextMoveToPoint(ctx, 0, 400);
    CGContextAddLineToPoint(ctx, 320, 400);
    CGContextAddLineToPoint(ctx, 160, 560);
    CGContextClosePath(ctx);//闭合路径
    // 一个控制点的贝塞尔曲线
    CGContextAddQuadCurveToPoint(ctx, 80, 100, 160, 300);
    // 两个控制点的贝塞尔曲线
    CGContextAddCurveToPoint(ctx, 80, 100, 240, 500, 320, 300);
    // 弧线
    CGContextAddArc(ctx, 240, 200, 80, 0, M_PI_2, NO);
    // 绘制图片
    CGRect imageFrame = CGRectMake(10, 30, 300, 300);
    // 获取图片数据
    NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"png"]; 
    UIImage *img = [UIImage imageWithContentsOfFile:imagePath];
    // 设置上下文当前转换矩阵(CTM),否则图片倒置
    CGContextTranslateCTM(context, 0, imageFrame.size.height);
    CGContextScaleCTM(context, 1, -1);
    CGContextDrawImage(context, imageFrame, img.CGImage); // 绘制
    // 或者如下绘制,不需要设置CTM
    [img drawInRect:imageFrame];

设置图形的属性(颜色、线条……)

    CGContextSetLineWidth(ctx, 5); // 线宽
    CGContextSetFillColorWithColor(ctx, [UIColor blueColor].CGColor); // 填充颜色
    CGContextSetStrokeColorWithColor(ctx, [UIColor whiteColor].CGColor); // 线条颜色
    CGContextSetShouldAntialias(ctx, YES); // 抗锯齿
    CGContextSetLineCap(ctx, kCGLineCapRound); // 线头颜色
    CGContextSetLineJoin(ctx, kCGLineJoinBevel); // 链接点样式

绘图(填充)

    CGContextFillPath(ctx);    // 填充
    CGContextStrokePath(ctx); // 描边
    绘制描边、填充、描边和填充、奇偶填充:		 
kCGPathFill,kCGPathEOFill,kCGPathStroke,kCGPathFillStroke, kCGPathEOFillStroke
    CGContextDrawPath(cxt, kCGPathFillStroke);

保存上下文状态(入栈)

    CGContextSaveGState(cxt);

恢复上下文状态(出栈)

    CGContextRestoreGState(cxt);

##6、使用UIBezierPath绘图

UIKit中的UIBezierPath是Core Graphics框架关于path的一个封装(封装为OC的方法)。 使用UIBezierPath绘图不需要手动获取绘图上下文,当drawRect方法被调用时,UIView的绘图上下文属于当前图形上下文。

实例化一个path对象

    // 不设置图形路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    // 矩形路径
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 100, 200, 200)];
    // 内切圆\椭圆路径
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 100, 200, 200)];
    //圆角矩形路径 
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 100, 200, 200) cornerRadius:20];
    // 弧线路径,ArcCenter:原点、radius:半径、startAngle:起点弧度、endAngle:终端弧度、clockwise:是否顺时针
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 100) radius:50 startAngle:0 endAngle:M_PI_2 clockwise:YES];

设置虚线: dashs: 虚线的虚实线的长度,count: 虚线的组成段数, phase: 设置虚线的起始位置

     [path setLineDash:dashs count:3 phase:0];

添加路径

    // 移动到某个点
    [path moveToPoint:p1];

    // 添加一条线到某个点
    [path addLineToPoint:p2];

    // 添加一条贝塞尔曲线
    [path addQuadCurveToPoint:p1 controlPoint:p2];

    // 添加一条弧线
    [path addArcWithCenter:p1 radius:50 startAngle:M_PI_4 endAngle:M_PI_2 clockwise:YES];

    // 闭合路径
    [path closePath];    

    // 移除所有的点
    [path removeAllPoints];

设置路径属性

    // 设置填充颜色
    [[UIColor redColor] setFill]; 

    // 设置描边颜色
   [[UIColor whiteColor] setStroke]; 

   // 线宽
    path.lineWidth = 5; 

    // 线头样式
    path.lineCapStyle = kCGLineCapRound;

    // 线连接点样式
    path.lineJoinStyle = kCGLineJoinMiter;

    // 连接点的斜距(角的内点和外点的距离),连接样式得为kCGLineJoinMiter
    path.miterLimit = 20;

绘图(填充)

    [path fill];    // 填充
    [path stroke];  // 描边

Demo下载地址:

https://github.com/fuxinto/HfxDemo

转载于:https://my.oschina.net/6603044/blog/740979

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值