前面我们讲了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);
}
-
UIGraphicsGetCurrentContext()
开启上下文,可以理解为打开一个画布。 -
CGContextBeginPath
开始一个起始路径 -
CGContextMoveToPoint
起始点设置 -
CGContextMoveToPoint
连接下一个坐标点 -
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
里面。
-
UIGraphicsGetCurrentContext()
开启上下文,可以理解为打开一个画布。 -
CGContextSetStrokeColorWithColor
设置虚线颜色 -
CGContextSetLineWidth
设置线条宽度 -
CGContextMoveToPoint(context, 0, 110)
设置虚线绘制起点 -
CGContextAddLineToPoint
绘制虚线终点 -
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<NSAttributedStringKey, id> *)attrs API_AVAILABLE(macos(10.0), ios(7.0));
- (void)drawInRect:(CGRect)rect withAttributes:(nullable NSDictionary<NSAttributedStringKey, id> *)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);
}
-
CGContextAddArc
绘制圆的关键代码。方法全名:CGContextAddArc(CGContextRef cg_nullable c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)
各参数:
-
(x, y)
表示圆的中心点 -
startAngle
起始角度 -
endAngle
结束角度 -
clockwise
顺时针/逆时针
-
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); //根据坐标绘制路径
}
-
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 <QuartzCore/QuartzCore.h>,这个就不属于在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
}
-
CGContextStrokeRect()
绘制方框,也就是矩形 -
CGContextFillRect
绘制一个填充框,默认颜色黑色 -
CGContextSetFillColorWithColor
设置线条填充颜色 -
CGContextSetStrokeColorWithColor
设置边框颜色 -
CGContextAddRect
画方框(和1,2不一样) -
CAGradientLayer
渐变色填充,其实就是自己写一个渐变色的layer,添加到视图上 -
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画图)