iOS Quartz 2D绘图知识详解

来源:互联网 发布:vb 字符串拷贝函数 编辑:程序博客网 时间:2024/04/28 07:06

* 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 Context7. 而Quartz 2D的容器就是CGContextRef数据模型。这种数据模型是C的结构体,存储了渲染到屏幕上需要的一切信息。

二、Quartz 2D详解:

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

1. CGPathRef 路径类型,用来绘制路径(注意带有ref后缀的一般都是绘制的画板)2. CGImageRef,绘制bitmap3. 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 0
原创粉丝点击