iOS Quartz 2D绘图知识详解

* Quartz*
1. Mac OS X的Darwin核心之上的绘图层,有时候也认为是CoreGraphics。共有两种部分组成Quartz:
2. Quartz Compositor,合成视窗系统,管理和合成幕后视窗影像来建立Mac OS X使用者接口。
3. Quartz 2D,是iOS和Mac OS X环境下的二维绘图引擎。
涉及内容包括:基于路径的绘图,透明度绘图,遮盖,阴影,透明层,颜色管理,防锯齿渲染,生成PDF,以及PDF元数据相关处理。


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

1. 透明层(transparency layers) 
2. 阴影 基于path的绘图(path-based drawing)
3. 离屏渲染(offscreen rendering) 
4. 复杂的颜色处理(advanced color management) 
5. 抗锯齿渲染(anti-aliased rendering)
6. PDF创建,展示,解析(这部分不在这个系列之中) 配合Core Animation, OpenGL ES,UIKit完成复杂的功能 画板-The Graphics Context
7. 而Quartz 2D的容器就是CGContextRef数据模型。这种数据模型是C的结构体,存储了渲染到屏幕上需要的一切信息。

二、Quartz 2D详解:

Quartz 2D的基本数据类型:
Quartz 2D中的数据类型都是透明的,也就是说用户只需要使用即可,不需要实际访问其中的变量。具体的数据类型包括

1. CGPathRef 路径类型,用来绘制路径(注意带有ref后缀的一般都是绘制的画板)
2. CGImageRef,绘制bitmap
3. CGLayerRef,绘制layer,layer可复用,可离屏渲染
4. CGPatternRef,重复绘制
5. CGShadingRef和CGGradientRef,绘制渐变(例如颜色渐变)
6. CGFunctionRef,定义回调函数,CGShadingRef和CGGradientRef的辅助类型
7. CGColorRef and CGColorSpaceRef,定义如何处理颜色
8. CGFontRef,绘制文字

Quartz 2D的坐标

UIKit默认的坐标系统与Quartz不同。在UIKit中,原点位于左上角,y轴正方向为向下。UIView通过将修改Quartz的Graphics Context的CTM[原点平移到左下角,同时将y轴反转(y值乘以-1)]以使其与UIView匹配。这些都是系统自动帮我们完成。

三、直线/矩形

  1. 基本图形绘制需要的属性
1.获取当前上下文(context)(UIGraphicsGetCurrentContext)
2.设置颜色:
    CGContextSetFillColorWithColor:设置描边颜色
    CGContextSetFillColorWithColor:设置填充颜色
3. 画的范围
    CGContextStrokeRect:描边的范围
    CGContextFillRect:填充的范围
4.CGContextSetLineWidth:线宽
5.CGContextSetLineCap:线顶端的样式
6.CGContextSetLineJoin:线拐角的样式
7. 线的起始点:
    CGContextMoveToPoint:起点 
    CGContextAddLineToPoint:终点
8.CGContextFillPath :填充的路径
9.CGContextStrokePath:描边的路径

直线、矩形 demo

- (void)drawRect:(CGRect)rect {

    //1.获得当前context
    CGContextRef context = UIGraphicsGetCurrentContext();

    //设置颜色 (填充色和 描边的颜色)
    CGContextSetFillColorWithColor(context, [UIColor colorWithWhite:0.8 alpha:1].CGColor);
    CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);

    //设置描边线宽
    CGContextSetLineWidth(context, 20);

    //对矩形进行填色  或  描边
    //(注意:如果先描边再填充,由于矩形大小一致,那么描边的线就会被填充的矩形挡住)
    CGContextFillRect(context, rect);
    CGContextStrokeRect(context, rect);

    //-----------------------------------------------------------------

    //MARK: ------ 实际line和point的代码
    // 设置描边颜色
    CGContextSetStrokeColorWithColor(context, [UIColor yellowColor].CGColor);    CGContextSetLineWidth(context, 8.0);//线的宽度
    CGContextSetLineCap(context, kCGLineCapRound);//线的顶端
    CGContextSetLineJoin(context, kCGLineJoinRound);//线相交的模式

    //-----------------------------------------------------------------
    //MARK:黄色的  ">" 图形
    //移动画笔到哪个点
    CGContextMoveToPoint(context,20,20);
    //画笔画到哪个点
    CGContextAddLineToPoint(context, rect.size.width - 20, rect.size.height / 2 - 20);
    CGContextAddLineToPoint(context, 20, rect.size.height - 20);
    //根据上下文中的点,成线进行描边
    CGContextStrokePath(context);

    //------------------------------------------------------------------
    //MARK: 红色的小的三角的填充
    CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
    CGContextMoveToPoint(context, 0, rect.size.height / 2 - 30);
    CGContextAddLineToPoint(context, 30, rect.size.height / 2);
    CGContextAddLineToPoint(context, 0, rect.size.height / 2 + 30);
    CGContextFillPath(context);
   //虚线效果
  //CGContextSetLineDash(context, 1, lengths, 1);

 //------------------------------------------------------------------
    //MARK: 红色虚线效果
    CGContextSetStrokeColorWithColor(context,[UIColor redColor].CGColor);
    CGContextSetLineWidth(context, 1);

    CGContextMoveToPoint(context, rect.size.width - 20, 20);
    CGContextAddLineToPoint(context, rect.size.height - 20, rect.size.width - 20);
    CGFloat lengths[] = {20};
    CGContextSetLineDash(context, 1, lengths, 1);
    CGContextStrokePath(context);
}

运行之后的效果:

虚线效果

CGContextSetLineDash参数详解
void CGContextSetLineDash (
CGContextRef _Nullable c,
CGFloat phase,
const CGFloat * _Nullable lengths,
size_t count
);
c 绘制的context,这个不用多说
phase,第一个虚线段从哪里开始,例如传入3,则从第三个单位开始
lengths,一个C数组,表示绘制部分和空白部分的分配。例如传入[2,2],则绘制2个单位,然后空白两个单位,以此重复
count lengths的数量


四、曲线— 圆弧的绘制

Quartz提供了两个方法来绘制圆弧
1. CGContextAddArc,普通的圆弧一部分(以某圆心,某半径,某弧度的圆弧)
2. CGContextAddArcToPoint,用来绘制圆角


  1. CGContextAddArc

  1. 结构:
    void CGContextAddArc (
    CGContextRef _Nullable c,
    CGFloat x, // 圆心X坐标
    CGFloat y, // 圆心Y坐标
    CGFloat radius, // 弧度半径
    CGFloat startAngle, // 开始的弧度
    CGFloat endAngle, // 结束的弧度
    int clockwise //1表示顺时针,0表示逆时针
    );

- (void)drawRect:(CGRect)rect {
    //--------------------------------------------------------------------
    //MARK: 画弧
    //1.获取图片上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    //2.设置弧度及位置
     //根据中心点,半径,起始的弧度,最后的弧度,是否顺时针画一个圆弧
    CGContextAddArc(context, rect.size.width / 2, rect.size.height / 2, 20, M_PI_4, M_PI, 1);
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
    //3.画
    CGContextDrawPath(context, kCGPathStroke);

    // -----------------------------------------------------

    //MARK:画有线圈的圆饼
    CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);//设置线的颜色
    CGContextSetRGBFillColor(context, 0, 0, 1, 1);//设置填充颜色
    CGContextSetLineWidth(context, 2); //设置线的宽度
    CGContextAddEllipseInRect(context, CGRectMake(10, 30, 60, 60)); //画一个椭圆或者圆
    CGContextDrawPath(context, kCGPathFillStroke);
}

2.CGContextAddArcToPoint

void CGContextAddArcToPoint (
CGContextRef _Nullable c,
CGFloat x1,
CGFloat y1,
CGFloat x2,
CGFloat y2,
CGFloat radius
);
c context x1,y1和当前点(x0,y0)决定了第一条切线(x0,y0)->(x1,y1) x2,y2和(x1,y1)决定了第二条切线 radius,想切的半径。
也就是说,
绘制一个半径为radius的圆弧,和上述 两条直线都相切。

- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1);//设置线的颜色
    CGContextSetRGBFillColor(ctx, 0, 0, 1, 1);//设置填充颜色
    CGContextSetLineWidth(ctx, 2); //设置线的宽度

    //CGContextAddArcToPoint 先要确定三个点,
    //1.从哪里开始划线 CGContextMoveToPoint (也就是两条线的交点)
    //2.第二个点与起始点  确定一条直线
    //3.第三个点与第二个点  确定另外一条直线

    //画一个圆角矩形
    //确定矩形的位置和大小
    CGRect rrect = CGRectMake(rect.size.width / 2 - 30, rect.size.height / 2 - 30, 60.0, 60.0);

    CGFloat radius = 15.0;//半径,半径为正方形一半时,那就可以切成圆形

    CGFloat
    minx = CGRectGetMinX(rrect),//矩形中最小的x
    midx = CGRectGetMidX(rrect),//矩形中最大x值的一半
    maxx = CGRectGetMaxX(rrect);//矩形中最大的x值

    CGFloat
    miny = CGRectGetMinY(rrect),//矩形中最小的Y值
    midy = CGRectGetMidY(rrect),//矩形中最大Y值的一半
    maxy = CGRectGetMaxY(rrect);//矩形中最大的Y值


    CGContextMoveToPoint(ctx, minx, midy);//从点A 开始
    //从点A到点B再从点B到点C形成夹角进行切圆
    CGContextAddArcToPoint(ctx, minx, miny, midx, miny, radius);
    CGContextAddArcToPoint(ctx, maxx, miny, maxx, midy, radius);
    CGContextAddArcToPoint(ctx, maxx, maxy, midx, maxy, radius);
    CGContextAddArcToPoint(ctx, minx, maxy, minx, midy, radius);
    CGContextClosePath(ctx);
    CGContextDrawPath(ctx, kCGPathFillStroke);
}

运行效果:

贝塞尔曲线

- (void)drawRect:(CGRect)rect {

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
    CGContextSetLineWidth(context, 4);


    CGFloat
    minx = CGRectGetMinX(rect),//矩形中最小的x
    midx = CGRectGetMidX(rect),//矩形中最大x值的一半
    maxx = CGRectGetMaxX(rect);//矩形中最大的x值

    CGFloat
    miny = CGRectGetMinY(rect),//矩形中最小的Y值
    midy = CGRectGetMidY(rect),//矩形中最大Y值的一半
    maxy = CGRectGetMaxY(rect);//矩形中最大的Y值

    //贝塞尔曲线一,两个控制点 红色
    CGPoint s = CGPointMake(minx + 10, miny + 10); //起始点
    CGPoint e = CGPointMake(maxx - 10, maxy - 10);//终点
    CGPoint cp1 = CGPointMake(miny, midy);//控制点1
    CGPoint cp2 = CGPointMake(midy, minx);//控制点2
    CGContextMoveToPoint(context, s.x, s.y);
    CGContextAddCurveToPoint(context, cp1.x, cp1.y, cp2.x, cp2.y, e.x, e.y);
    CGContextStrokePath(context);

    //贝塞尔曲线二,一个控制点 蓝色
    CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
    s = CGPointMake(minx, maxy);
    e = CGPointMake(maxx, maxy);
    cp1 = CGPointMake(midx, midy);
    CGContextMoveToPoint(context, s.x, s.y);
    CGContextAddQuadCurveToPoint(context, cp1.x, cp1.y, e.x, e.y);
    CGContextStrokePath(context);
}

运行效果

五、颜色渐变
demo

- (void)drawRect:(CGRect)rect {
    // Drawing code

    // 创建Quartz上下文
    CGContextRef context = UIGraphicsGetCurrentContext();

    // 创建色彩空间对象
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();

    // 创建起点颜色
    CGColorRef beginColor = CGColorCreate(colorSpaceRef, (CGFloat[]){0.01f, 0.5f, 0.01f, 1.0f});

    // 创建终点颜色
    CGColorRef endColor = CGColorCreate(colorSpaceRef, (CGFloat[]){0.99f, 0.99f, 0.01f, 1.0f});

    // 创建颜色数组
    const void **values = (const void*[]){beginColor, endColor};//颜色数组
    CFArrayRef colorArray = CFArrayCreate(
                                          kCFAllocatorDefault,
                                          values,//颜色数组
                                          2,//数组的个数
                                          nil// CGGradientCreateWithColors的最后一个locations参数可以传空,这样默认为从0.0到1.0。
                                          );

    // 创建渐变对象
    CGGradientRef gradientRef = CGGradientCreateWithColors(colorSpaceRef, colorArray, (CGFloat[]){
        0.0f,       // 对应起点颜色位置
        1.0f        // 对应终点颜色位置
    });

    // 释放颜色数组
    CFRelease(colorArray);

    // 释放起点和终点颜色
    CGColorRelease(beginColor);
    CGColorRelease(endColor);

    // 释放色彩空间
    CGColorSpaceRelease(colorSpaceRef);

    /*
     1.context          上线文
     2.gradientRef      颜色数组
     3.startPoint       开始位置
     4.endPoint         结束位置
     5.CGGradientDrawingOptions         
     当你的起点或者终点不在图形上下文的边缘内时,指定该如何处理。你可以使用你的开始或结束颜色来填充渐变以外的空间。此参数为以下值之一:
     KCGGradientDrawsAfterEndLocation扩展整个渐变到渐变的终点之后的所有点 
     KCGGradientDrawsBeforeStartLocation扩展整个渐变到渐变的起点之前的所有点。
     0不扩展该渐变。
     */
    CGPoint startPoint = CGPointMake(0.0f, 0.0f);
    CGPoint endPoint = CGPointMake(rect.size.width, rect.size.height);
    CGGradientDrawingOptions options = kCGGradientDrawsAfterEndLocation;
    CGContextDrawLinearGradient(
                                context,
                                gradientRef,
                                startPoint,
                                endPoint,
                                kCGGradientDrawsBeforeStartLocation
//                                kCGGradientDrawsAfterEndLocation
                                );


    // 释放渐变对象
    CGGradientRelease(gradientRef);
}

效果图

六、多中颜色的渲染
demo

- (void)drawRect:(CGRect)rect {
    // 创建Quartz上下文
    CGContextRef context = UIGraphicsGetCurrentContext();

    // 创建色彩空间对象
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();

    // 创建渐变对象
    CGGradientRef gradientRef =
    CGGradientCreateWithColorComponents(colorSpaceRef,
                                        (CGFloat[]){
                                         1.0f,0.8f,0.5f,1.0f,//第一个颜色RGB 和透明度
                                         0.6f,0.5f,0.6f,1.0f,//第二个颜色RGB 和透明度
                                         0.3f,0.2f,0.f,1.0f,//第三个颜色RGB 和透明度
                                         .0f,0.0f,0.3f,1.0f
                                        },
                                        (CGFloat[]){  0.0f,0.3f,.6f,1},//颜色渐变的位置
                                        4);//颜色的个数

    // 释放色彩空间
    CGColorSpaceRelease(colorSpaceRef);

    // 填充渐变色
    CGContextDrawLinearGradient(context, gradientRef, CGPointMake(0.0f, 0.0f), CGPointMake(320.0f, 460.0f), 0);

    // 释放渐变对象
    CGGradientRelease(gradientRef);
}

效果

几何图形绘制属性—详解
1.Graphics Context(图层上下文)

  1. Graphics Context
    其实就是表示了一个绘制目标,也就是你打算绘制的地方,它包含绘制系统用于完成绘制指令的绘制参数和设备相关信息。Graphics Context定义了基本的绘制属性,如颜色、裁减区域、线条宽度和样式信息、字体信息、混合模式等。
  2. *获取Graphics Context:
    1. Quartz提供的创建函数、Mac OS X框架或IOS的UIKit框架提供的函数。Quartz提供了多种Graphics Context的创建函数,包括bitmap和PDF,我们可以使用这些Graphics Context创建自定义的内容。
    2. 在代码中,我们用CGContextRef来表示一个Graphics Context。当获得一个Graphics Context后,可以使用Quartz 2D函数在上下文(context)中进行绘制、完成操作(如平移)、修改图形状态参数(如线宽和填充颜色)等。

查阅的资料
感谢大家在博客或者简书的分享,我在这里做了总结和扩展,仅供大家学习和讨论,如果有什么不对的请大家及时留言评论,谢谢~
本人github账号: 702029772@qq.com

  1. 博主:zenny_chen http://www.cnblogs.com/zenny-chen/archive/2012/02/23/2364152.html
  2. 博主:贱见 https://account.aliyun.com/login/login.htm?from_type=yqclub&oauth_callback=https%3A%2F%2Fyq.aliyun.com%2Fusers%2F1482959332945947%3Fspm%3D5176.100239.blogrightarea35932.3.0TK01t%26do%3Dlogin
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值