iOS-CGContextRef开启上下文绘图

前面我们讲了UIBezierPath绘图,UIBezierPath只能画线,描绘几何图形。CGContextRef相当于一个画布,可以绘制任意图形。

文字、圆、直线、弧线、矩形、扇形、椭圆、三角形、圆角矩形、图片

前文回顾:
iOS-贝塞尔曲线(UIBezierPath)的基本使用
iOS-贝塞尔曲线(UIBezierPath)详解(CAShapeLayer)
iOS-UIBezierPath动画之果冻动画

我们通过几个例子来介绍CGContextRef的常用方法!

绘制一条折线

先看效果图:


折线图
- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    
    //获得处理的上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    //设置线条样式
    CGContextSetLineCap(context, kCGLineCapSquare);
    //设置线条粗细宽度
    CGContextSetLineWidth(context, 3.0);
    //设置颜色
    CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
    //开始一个起始路径
    CGContextBeginPath(context);
    //起始点设置为(100, 100)
    CGContextMoveToPoint(context, 100, 100);
    //设置下一个坐标点
    CGContextAddLineToPoint(context, 200, 200);
    //设置下一个坐标点
    CGContextAddLineToPoint(context, 100, 250);
    //设置下一个坐标点
    CGContextAddLineToPoint(context, 150, 280);
    //连接上面定义的坐标点
    CGContextStrokePath(context);
}
  1. UIGraphicsGetCurrentContext()开启上下文,可以理解为打开一个画布。
  2. CGContextBeginPath开始一个起始路径
  3. CGContextMoveToPoint起始点设置
  4. CGContextMoveToPoint连接下一个坐标点
  5. CGContextAddLineToPoint绘制虚线终点
画一条虚线

先看效果

一条虚线
- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
        
    CGContextRef context = UIGraphicsGetCurrentContext();
    //设置虚线颜色
    CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
    //设置虚线宽度
    CGContextSetLineWidth(context, 1);
    //设置虚线绘制起点
    CGContextMoveToPoint(context, 0, 110);
    //设置虚线绘制终点
    CGContextAddLineToPoint(context, self.frame.origin.x + self.frame.size.width, 110);
    //设置虚线排列的宽度间隔:下面的arr中的数字表示先绘制3个点再绘制1个点
    CGFloat arr[] = {3,1};
    //下面最后一个参数“2”代表排列的个数。
    CGContextSetLineDash(context, 0, arr, 2);
    CGContextDrawPath(context, kCGPathStroke);
}

从代码可以看出来CGContextRef还是写在方法- (void)drawRect:(CGRect)rect里面。

  1. UIGraphicsGetCurrentContext()开启上下文,可以理解为打开一个画布。
  2. CGContextSetStrokeColorWithColor设置虚线颜色
  3. CGContextSetLineWidth设置线条宽度
  4. CGContextMoveToPoint(context, 0, 110)设置虚线绘制起点
  5. CGContextAddLineToPoint绘制虚线终点
  6. CGContextSetLineDash绘制虚线的间隔
    方法名:CGContextSetLineDash(CGContextRef cg_nullable c, CGFloat phase, const CGFloat * __nullable lengths, size_t count)
  • lengths的值{10,10}表示先绘制10个点,再跳过10个点,如此反复。
  • 如果把lengths值改为{10, 20, 10},则表示先绘制10个点,跳过20个点,绘制10个点,跳过10个点,再绘制20个点,如此反复。
  • phase参数表示在第一个虚线绘制的时候跳过多少个点
  • count表示lengths的长度(个数)
    more:关于CGContextSetLineDash的使用方法,如果还不清楚,可以参考一个文章:绘制虚线 CGContextSetLineDash的使用,我觉得写的不错。

绘制多条线段

先看效果图:


多条线段

使用方法如下:

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
        
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //设置画笔属性
    CGContextSetStrokeColorWithColor(ctx, [UIColor whiteColor].CGColor);
    CGContextSetFillColorWithColor(ctx, [UIColor clearColor].CGColor);
    CGContextSetLineWidth(ctx, 1);
    CGContextSetLineJoin(ctx, kCGLineJoinRound);
    
    CGPoint point = CGPointMake(kScreenWidth/2, kScreenWidth/2);
    CGContextMoveToPoint(ctx, kScreenWidth/2, kScreenWidth/2-100);
    CGContextAddLineToPoint(ctx, point.x, point.y);
    
    CGContextMoveToPoint(ctx, kScreenWidth/2-100, kScreenWidth/2);
    CGContextAddLineToPoint(ctx, point.x, point.y);
    
    CGContextMoveToPoint(ctx, kScreenWidth/2+50, kScreenWidth/2+50);
    CGContextAddLineToPoint(ctx, point.x, point.y);
    
    CGContextMoveToPoint(ctx, kScreenWidth/2+100, kScreenWidth/2-50);
    CGContextAddLineToPoint(ctx, point.x, point.y);
    
    CGContextStrokePath(ctx);
}
  • CGContextSetLineJoin设置线条拐点的样式
    从代码可以看出来,我们可以在一个画板里面绘制多条直线。
    可以利用这个特性,绘制一些图表:分布图。。。
文字绘制

系统提供了绘制文字的两个方法:

- (void)drawAtPoint:(CGPoint)point withAttributes:(nullable NSDictionary *)attrs API_AVAILABLE(macos(10.0), ios(7.0));
- (void)drawInRect:(CGRect)rect withAttributes:(nullable NSDictionary *)attrs API_AVAILABLE(macos(10.0), ios(7.0));

效果图如下:


文字

使用方法如下:

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
        
    CGContextRef context = UIGraphicsGetCurrentContext();
    /*写文字*/
    CGContextSetRGBFillColor (context,  1, 0, 0, 1.0);//设置填充颜色
    UIFont *font = [UIFont boldSystemFontOfSize:15.0];//设置
    
     NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:15], NSForegroundColorAttributeName:[UIColor whiteColor]};
    [@"这是一条文字:" drawInRect:CGRectMake(110, 120, 180, 20) withAttributes:attributes];
    [@"画线及孤线:" drawInRect:CGRectMake(110, 180, 100, 20) withAttributes:@{NSFontAttributeName:font}];

    CGContextStrokePath(context);
}
画圆

我们会发现CGContextRef和贝塞尔曲线的画法,有相似之处。
画圆也是,效果图如下:


画圆
- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
        
    CGContextRef context = UIGraphicsGetCurrentContext();
    //边框圆
    CGContextSetRGBStrokeColor(context,1,1,1,1.0);//画笔线的颜色
    CGContextSetLineWidth(context, 1.0);//线的宽度
    //void CGContextAddArc(CGContextRef c,CGFloat x, CGFloat y,CGFloat radius,CGFloat startAngle,CGFloat endAngle, int clockwise)1弧度=180°/π (≈57.3°) 度=弧度×180°/π 360°=360×π/180 =2π 弧度
    // x,y为圆点坐标,radius半径,startAngle为开始的弧度,endAngle为 结束的弧度,clockwise 0为顺时针,1为逆时针。
    CGContextAddArc(context, 100, 120, 15, 0, 2 * M_PI, 0); //添加一个圆
    CGContextDrawPath(context, kCGPathStroke); //绘制路径
    
    //填充圆,无边框
    CGContextAddArc(context, 150, 130, 30, 0, 2*M_PI, 0); //添加一个圆
    CGContextDrawPath(context, kCGPathFill);//绘制填充
    
    //画大圆并填充颜
    UIColor *aColor = [UIColor colorWithRed:1 green:0.0 blue:0 alpha:1];
    CGContextSetFillColorWithColor(context, aColor.CGColor);//填充颜色
    CGContextSetLineWidth(context, 3.0);//线的宽度
    CGContextAddArc(context, 250, 140, 40, 0, 2*M_PI, 0); //添加一个圆
    //kCGPathFill填充非零绕数规则,kCGPathEOFill表示用奇偶规则,kCGPathStroke路径,kCGPathFillStroke路径填充,kCGPathEOFillStroke表示描线,不是填充
    CGContextDrawPath(context, kCGPathFillStroke); //绘制路径加填充
    
    CGContextStrokePath(context);
}

  1. CGContextAddArc绘制圆的关键代码。方法全名:CGContextAddArc(CGContextRef cg_nullable c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)
    各参数:
  • (x, y)表示圆的中心点
  • startAngle起始角度
  • endAngle结束角度
  • clockwise顺时针/逆时针
  1. CGContextSetFillColorWithColor表示填充颜色
画直线

刚刚画折线的方法就可以画直线,即:CGContextAddLineToPoint方法。
但是还有一种更特殊的方法,可以画直线。

效果图:

直线

使用方法如下:

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
        
    CGContextRef context = UIGraphicsGetCurrentContext();    
    //画线
    CGContextSetRGBStrokeColor(context, 1, 1, 1, 1);//改变画笔颜色
    CGPoint aPoints[2];//坐标点
    aPoints[0] = CGPointMake(100, 80);//坐标1
    aPoints[1] = CGPointMake(230, 80);//坐标2
    //CGContextAddLines(CGContextRef c, const CGPoint points[],size_t count)
    //points[]坐标数组,和count大小
    CGContextAddLines(context, aPoints, 2);//添加线
    CGContextDrawPath(context, kCGPathStroke); //根据坐标绘制路径    
}
  1. CGContextAddLines绘制数组中的点。方法全名CGContextAddLines(CGContextRef cg_nullable c, const CGPoint * __nullable points, size_t count)

参数points表示一个点的集合
参数count表示点的个数

more:思考一下,如果这个集合里面有多个点,会怎么样?评论区留言哟~

画曲线

我们画一个笑脸,还看看曲线怎么画?
效果图:

笑脸

这个笑脸就是单个曲线组合而成。
使用方法如下:

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
        
    CGContextRef context = UIGraphicsGetCurrentContext();
     
    //画笑脸弧线
    //左
    CGContextSetRGBStrokeColor(context, 1, 1, 1, 1);//改变画笔颜色
    CGContextMoveToPoint(context, 140, 80);//开始坐标p1
    //CGContextAddArcToPoint(CGContextRef c, CGFloat x1, CGFloat y1,CGFloat x2, CGFloat y2, CGFloat radius)
    //x1,y1跟p1形成一条切线(切点p2),x2,y2跟x1,y1形成一条切线(切点p3),radius半径,注意, 需要算好半径的长度,
    CGContextAddArcToPoint(context, 148, 68, 156, 80, 10);
    CGContextStrokePath(context);//绘画路径

    //右
    CGContextMoveToPoint(context, 160, 80);//开始坐标p1
    //CGContextAddArcToPoint(CGContextRef c, CGFloat x1, CGFloat y1,CGFloat x2, CGFloat y2, CGFloat radius)
    //x1,y1跟p1形成一条切线(切点p2),x2,y2跟x1,y1形成一条切线(切点p3),radius半径,注意, 需要算好半径的长度,
    CGContextAddArcToPoint(context, 168, 68, 176, 80, 10);
    CGContextStrokePath(context);//绘画路径

    //下
    CGContextMoveToPoint(context, 150, 90);//开始坐标p1
    //CGContextAddArcToPoint(CGContextRef c, CGFloat x1, CGFloat y1,CGFloat x2, CGFloat y2, CGFloat radius)
    //x1,y1跟p1形成一条切线(切点p2),x2,y2跟x1,y1形成一条切线(切点p3),radius半径,注意, 需要算好半径的长度,
    CGContextAddArcToPoint(context, 158, 102, 166, 90, 10);
    
    CGContextStrokePath(context);
}

CGContextAddArcToPoint(CGContextRef c, CGFloat x1, CGFloat y1,CGFloat x2, CGFloat y2, CGFloat radius): x1,y1跟p1形成一条切线(切点p2),x2,y2跟x1,y1形成一条切线(切点p3),radius半径。注意: 需要算好半径的长度,

填充颜色

我们画一个矩形,填充纯色和渐变色。效果图如下:


填充颜色

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
        
    CGContextRef context = UIGraphicsGetCurrentContext();
     
    /*画矩形*/
    CGContextStrokeRect(context,CGRectMake(100, 120, 10, 10));//画方框
    CGContextFillRect(context,CGRectMake(120, 120, 10, 10));//填充框
    //矩形,并填弃颜色
    CGContextSetLineWidth(context, 2.0);//线的宽度
    CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);//填充颜色
    CGContextSetStrokeColorWithColor(context, [UIColor yellowColor].CGColor);//线框颜色
    CGContextAddRect(context,CGRectMake(140, 120, 60, 30));//画方框
    CGContextDrawPath(context, kCGPathFillStroke);//绘画路径
    
    //矩形,并填弃渐变颜色
    //第一种填充方式,第一种方式必须导入类库quartcore并#import ,这个就不属于在context上画,而是将层插入到view层上面。那么这里就设计到Quartz Core 图层编程了。
    CAGradientLayer *gradient1 = [CAGradientLayer layer];
    gradient1.frame = CGRectMake(240, 120, 60, 30);
    gradient1.colors = [NSArray arrayWithObjects:(id)[UIColor whiteColor].CGColor,
                        (id)[UIColor grayColor].CGColor,
                        (id)[UIColor blackColor].CGColor,
                        (id)[UIColor yellowColor].CGColor,
                        (id)[UIColor blueColor].CGColor,
                        (id)[UIColor redColor].CGColor,
                        (id)[UIColor greenColor].CGColor,
                        (id)[UIColor orangeColor].CGColor,
                        (id)[UIColor brownColor].CGColor,nil];
    [self.layer insertSublayer:gradient1 atIndex:0];
    //第二种填充方式
    CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
    CGFloat colors[] =
    {
        1,1,1, 1.00,
        1,1,0, 1.00,
        1,0,0, 1.00,
        1,0,1, 1.00,
        0,1,1, 1.00,
        0,1,0, 1.00,
        0,0,1, 1.00,
        0,0,0, 1.00,
    };
    CGGradientRef gradient = CGGradientCreateWithColorComponents
    (rgb, colors, NULL, sizeof(colors)/(sizeof(colors[0])*4));//形成梯形,渐变的效果
    CGColorSpaceRelease(rgb);
    //画线形成一个矩形
    //CGContextSaveGState与CGContextRestoreGState的作用
    /*
     CGContextSaveGState函数的作用是将当前图形状态推入堆栈。之后,您对图形状态所做的修改会影响随后的描画操作,但不影响存储在堆栈中的拷贝。在修改完成后,您可以通过CGContextRestoreGState函数把堆栈顶部的状态弹出,返回到之前的图形状态。这种推入和弹出的方式是回到之前图形状态的快速方法,避免逐个撤消所有的状态修改;这也是将某些状态(比如裁剪路径)恢复到原有设置的唯一方式。
     */
    CGContextSaveGState(context);
    CGContextMoveToPoint(context, 220, 90);
    CGContextAddLineToPoint(context, 240, 90);
    CGContextAddLineToPoint(context, 240, 110);
    CGContextAddLineToPoint(context, 220, 110);
    CGContextClip(context);//context裁剪路径,后续操作的路径
    //CGContextDrawLinearGradient(CGContextRef context,CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint,CGGradientDrawingOptions options)
    //gradient渐变颜色,startPoint开始渐变的起始位置,endPoint结束坐标,options开始坐标之前or开始之后开始渐变
    CGContextDrawLinearGradient(context, gradient,CGPointMake
                                (220,90) ,CGPointMake(240,110),
                                kCGGradientDrawsAfterEndLocation);
    CGContextRestoreGState(context);// 恢复到之前的context
    
    //再写一个看看效果
    CGContextSaveGState(context);
    CGContextMoveToPoint(context, 260, 90);
    CGContextAddLineToPoint(context, 280, 90);
    CGContextAddLineToPoint(context, 280, 100);
    CGContextAddLineToPoint(context, 260, 100);
    CGContextClip(context);//裁剪路径
    //说白了,开始坐标和结束坐标是控制渐变的方向和形状
    CGContextDrawLinearGradient(context, gradient,CGPointMake
                                (260, 90) ,CGPointMake(260, 100),
                                kCGGradientDrawsAfterEndLocation);
    CGContextRestoreGState(context);// 恢复到之前的context
}
  1. CGContextStrokeRect()绘制方框,也就是矩形
  2. CGContextFillRect绘制一个填充框,默认颜色黑色
  3. CGContextSetFillColorWithColor设置线条填充颜色
  4. CGContextSetStrokeColorWithColor设置边框颜色
  5. CGContextAddRect画方框(和1,2不一样)
  6. CAGradientLayer渐变色填充,其实就是自己写一个渐变色的layer,添加到视图上
  7. CGContextDrawLinearGradient gradient渐变颜色,startPoint开始渐变的起始位置,endPoint结束坐标,options开始坐标之前or开始之后开始渐变

大家可以看注释,注释写的很清楚

椭圆

效果图:


椭圆
- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    CGContextRef context = UIGraphicsGetCurrentContext();
    //画椭圆
    CGContextAddEllipseInRect(context, CGRectMake(120, 120, 200, 88)); //椭圆
    CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);//填充颜色
    CGContextDrawPath(context, kCGPathFillStroke);
}
曲线

二阶曲线,三阶曲线
效果图如下:


二阶曲线,三阶曲线
- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    CGContextRef context = UIGraphicsGetCurrentContext();
    /*画贝塞尔曲线*/
    //二次曲线
    CGContextMoveToPoint(context, 120, 300);//设置Path的起点
    CGContextAddQuadCurveToPoint(context,190, 310, 120, 390);//设置贝塞尔曲线的控制点坐标和终点坐标
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);//线框颜色
    CGContextSetLineWidth(context, 3.0);//线的宽度

    CGContextStrokePath(context);
    //三次曲线函数
    CGContextMoveToPoint(context, 200, 300);//设置Path的起点
    CGContextAddCurveToPoint(context,250, 280, 250, 400, 280, 300);//设置贝塞尔曲线的控制点坐标和控制点坐标终点坐标
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);//线框颜色
    CGContextSetLineWidth(context, 3.0);//线的宽度

    CGContextStrokePath(context);
}
图像绘制

我们可以将一张已有的icon,渲染到画布中:


图像绘制
- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    UIImage *image = [UIImage imageNamed:@"buttonS"];
    [image drawInRect:CGRectMake(60, 340, 20, 20)];//在坐标中画出图片
    // [image drawAtPoint:CGPointMake(100, 340)];//保持图片大小在point点开始画图片,可以把注释去掉看看
    CGContextDrawImage(context, CGRectMake(100, 340, 20, 20), image.CGImage);//使用这个使图片上下颠倒,镜像.参考http://blog.csdn.net/koupoo/article/details/8670024
}

CGContextDrawImage可以让图片镜像,上下颠倒。

给图像绘制文字

这个特殊需求

这个不属于本篇文章的介绍内容。
算是课后作业吧!大家运行一下看看结果吧!

不知道有人了解 Quart2D绘图吗???

+ (UIImage *)drawText1:(NSString *)text1 forImage:(UIImage *)image{
    CGSize size = CGSizeMake(image.size.width,image.size.height ); // 画布大小
    
    UIGraphicsBeginImageContextWithOptions(size,NO,0.0);
    
    [image drawAtPoint:CGPointMake(0,0)];
    // 获得一个位图图形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    CGContextDrawPath(context,kCGPathStroke);
    NSDictionary *attributes = @{ NSFontAttributeName:[UIFont systemFontOfSize:10], NSForegroundColorAttributeName:[UIColor redColor]};
   
    // 画文字 让文字处于居中模式
    [text1 drawAtPoint:CGPointMake(3,2) withAttributes:attributes];
    // 返回绘制的新图形
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return newImage;
}

关于CGContextRef的使用

这是从网上摘抄过来的,参考一下吧:

0 CGContextRef context = UIGraphicsGetCurrentContext(); 设置上下文
1 CGContextMoveToPoint 开始画线
2 CGContextAddLineToPoint 画直线
4 CGContextAddEllipseInRect 画一椭圆
4 CGContextSetLineCap 设置线条终点形状
4 CGContextSetLineDash 画虚线
4 CGContextAddRect 画一方框
4 CGContextStrokeRect 指定矩形
4 CGContextStrokeRectWithWidth 指定矩形线宽度
4 CGContextStrokeLineSegments 一些直线
5 CGContextAddArc 画已曲线 前俩店为中心 中间俩店为起始弧度 最后一数据为0则顺时针画 1则逆时针
5 CGContextAddArcToPoint(context,0,0, 2, 9, 40);//先画俩条线从point 到 弟1点 , 从弟1点到弟2点的线 切割里面的圆
6 CGContextSetShadowWithColor 设置阴影

7 CGContextSetRGBFillColor 这只填充颜色
7 CGContextSetRGBStrokeColor 画笔颜色设置
7 CGContextSetFillColorSpace 颜色空间填充
7 CGConextSetStrokeColorSpace 颜色空间画笔设置
8 CGContextFillRect 补充当前填充颜色的rect
8 CGContextSetAlaha 透明度
9 CGContextTranslateCTM 改变画布位置
10 CGContextSetLineWidth 设置线的宽度
11 CGContextAddRects 画多个线
12 CGContextAddQuadCurveToPoint 画曲线
13 CGContextStrokePath 开始绘制图片
13 CGContextDrawPath 设置绘制模式
14 CGContextClosePath 封闭当前线路
15 CGContextTranslateCTM(context, 0, rect.size.height); CGContextScaleCTM(context, 1.0, -1.0);反转画布
16 CGContextSetInterpolationQuality 背景内置颜色质量等级
16 CGImageCreateWithImageInRect 从原图片中取小图
17 字符串的 写入可用 nsstring本身的画图方法 - (CGSize)drawInRect:(CGRect)rect withFont:(UIFont )font lineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment;来写进去即可
18对图片放大缩小的功能就是慢了点 UIGraphicsBeginImageContext(newSize); UIImage
newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
19 CGColorGetComponents() 返回颜色的各个直 以及透明度 可用只读const float 来接收 是个数组

结语:

本文代码参考了IOS用CGContextRef画图)

你可能感兴趣的:(iOS-CGContextRef开启上下文绘图)