iOS绘图基础(draw)
先说几个基本概念:
- context:上下文,ios绘图的方法都需要传一个上下文context,这个context在重写uiview的drawRect的方法里调用UIGraphicsGetCurrentContext()获取
- path:路径,ios绘图可以想象为你拿着一支笔去画图,画几条线或几个点从而形成一个路径,之后可以利用理解去填色或者描边
- stroke,fill 描边和填充,每个路径都需要填充或者描边后才能在视图中看见,他们都各自有很多样式可以设置,常见的有颜色、粗细、渐变,连接样式等等。
- 画图可以使用默认路径画,或者单独创建path画图,对应画图的api并不完全相同,是两组名称相似的api,两组pi常用的方法如下
CGContextMoveToPoint设置起点
CGContextClosePath 连接起点和当前点
CGPathCreateMutable 类似于 CGContextBeginPath
CGPathMoveToPoint 类似于 CGContextMoveToPoint
CGPathAddLineToPoint 类似于 CGContextAddLineToPoint
CGPathAddCurveToPoint 类似于 CGContextAddCurveToPoint
CGPathAddEllipseInRect 类似于 CGContextAddEllipseInRect
CGPathAddArc 类似于 CGContextAddArc
CGPathAddRect 类似于 CGContextAddRect
CGPathCloseSubpath 类似于 CGContextClosePath
CGContextAddPath函数把一个路径添加到graphics
画图步骤
1:获取context,
2:设置路径
CGContextStrokePath(ctx); //描出路径
CGContextFillPath(ctx) 使用非零绕数规则填充当前路径
CGContextDrawPath 两个参数决定填充规则,kCGPathFill表示用非零绕数规则,kCGPathEOFill表示用奇偶规则,kCGPathFillStroke表示填充,kCGPathEOFillStroke表示描线,不是填充
CGContextEOFillPath 使用奇偶规则填充当前路径
CGContextFillRect 填充指定的矩形
CGContextFillRects 填充指定的一些矩形
CGContextFillEllipseInRect 填充指定矩形中的椭圆
3:填充或描边路径
关于填充颜色 填充颜色有3种模式,分别是1:填充笔触,就是只给路径描边,2:根据路径填充颜色 3:填充笔触和颜色。填充颜色也分为非零绕数规则和奇偶规则,这个概念比较复杂难以解释,大家可以百度看看或者花几个图试试就明白。
几种基础绘图的代码
1.准备工作
新建一个继承于UIView的类, 重写-(void)drawRect:(CGRect)rect; 方法
// 重写drawRect
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
// 1.获取上下文
CGContextRef contextRef = UIGraphicsGetCurrentContext();
/**********2.设置画图相关样式参数*********/
// 设置笔触的颜色
CGContextSetStrokeColorWithColor(contextRef, [UIColor blueColor].CGColor); // 设置颜色有很多方法,推荐这个
// 设置笔触的宽度
CGContextSetLineWidth(contextRef, 2);
// 设置填充色
CGContextSetFillColorWithColor(contextRef, [UIColor purpleColor].CGColor);
// 设置拐点样式
/**
* enum CGLineJoin {
* kCGLineJoinMiter, //尖的,斜接
* kCGLineJoinRound, //圆
* kCGLineJoinBevel //斜面
* }
*/
CGContextSetLineJoin(contextRef, kCGLineJoinRound);
// 设置线两端的样式
/**
* enum CGLineCap {
* kCGLineCapButt,
* kCGLineCapRound,
* kCGLineCapSquare
* };
*/
CGContextSetLineCap(contextRef, kCGLineCapRound);
// 设置虚线线条的样式
// CGFloat lengths[] = {10, 10};
// CGContextSetLineDash(contextRef, 0, lengths, 2);
/**********设置画图相关样式参数*********/
/**********3.开始画图*********/
// 画线
[self drawline:contextRef];
// 画圆,圆弧,贝塞尔曲线
[self drawCircle:contextRef];
// 画矩形,画椭圆,多边形
[self drawShape:contextRef];
// 画文字
[self drawText:contextRef];
// 画图片
[self drawPicture:contextRef];
/**********结束画图*********/
}
2.画线
第一个方法我写的比较详细,写了使用path的方式和直接画线的方式。推荐使用path的方式画线。 另外,第一个方法也写了移动笔触画线和用点集合画线。后面方法只会涉及其中一种,因为方法都比较类似。
- (void)drawline:(CGContextRef)contextRef
{
// 画一条简单的线
CGPoint points1[] = {CGPointMake(10, 30), CGPointMake(300, 30)};
CGContextAddLines(contextRef, points1, 2);
// 画线方法1, 使用CGContextAddLineToPoint添加点画线,需要先设置一个起始点
// 设置起始点
CGContextMoveToPoint(contextRef, 50, 50);
// 添加一个点
CGContextAddLineToPoint(contextRef, 100, 50);
// 在添加一个点,变成折现
CGContextAddLineToPoint(contextRef, 150, 100);
// 在添加一个点,再折一下
CGContextAddLineToPoint(contextRef, 280, 100);
// 画线方法2
// 构造线路的点数组
CGPoint points2[] = {CGPointMake(50, 120), CGPointMake(100, 150), CGPointMake(150, 120), CGPointMake(200, 150), CGPointMake(250, 120)};
CGContextAddLines(contextRef, points2, 5); // 最后一个参数为要绘制点的个数
// 画线方法3
// 利用路径去画一组点(推荐使用路径的方式,虽然多了几行代码,带上逻辑更加清晰了)
// 路径1
CGMutablePathRef path1 = CGPathCreateMutable();
CGPathMoveToPoint(path1, &CGAffineTransformIdentity, 30, 180); // 起始点, CGAffineTransformIdentity 类似于初始化一些参数
CGPathAddLineToPoint(path1, &CGAffineTransformIdentity, 30, 220); // 添加一个点
CGPathAddLineToPoint(path1, &CGAffineTransformIdentity, 80, 220); // 添加一个点
// 将路径1加入contextRef
CGContextAddPath(contextRef, path1);
// path同样有方法CGPathAddLines()添加一组路径,和CGContextAddLines()差不多
/******** 上面的方法都要写下面这两句代码 ********/
// 描出笔触
CGContextStrokePath(contextRef);
// 填充
CGContextFillPath(contextRef);
}
3. 画圆,圆弧,贝塞尔曲线
画圆和圆弧是一回事,只是起点和重点位置不同,画圆画弧线主要依赖于这几个方法CGContextAddArc,CGContextAddArcToPoint,CGContextAddCurveToPoint,CGContextAddQuadCurveToPoint后面两个方法是贝塞尔二次曲线和三次曲线
- (void)drawCircle:(CGContextRef)contextRef
{
// 画笔改成紫色,便于区别
CGContextSetStrokeColorWithColor(contextRef, [UIColor greenColor].CGColor);
/** 绘制路径 方法一
* void CGContextAddArc (
* CGContextRef c,
* CGFloat x, //圆心的x坐标
* CGFloat y, //圆心的x坐标
* CGFloat radius, //圆的半径
* CGFloat startAngle, //开始弧度
* CGFloat endAngle, //结束弧度
* int clockwise //0表示顺时针,1表示逆时针
* );
*/
// 圆
CGContextAddArc(contextRef, 100, 100, 50, 0, M_PI*2, 0);
CGContextStrokePath(contextRef);
// 半圆
CGContextAddArc(contextRef, 100, 200, 50, M_PI, M_PI*2, 0);
CGContextStrokePath(contextRef);
/**
* 绘制路径 方法二,这个方法适合绘制弧度,端点p1和p2是弧线的控制点,类似photoshop中的钢笔工具控制曲线,还不明白请去了解贝塞尔曲线
* void CGContextAddArcToPoint(
* CGContextRef c,
* CGFloat x1, //端点1的x坐标
* CGFloat y1, //端点1的y坐标
* CGFloat x2, //端点2的x坐标
* CGFloat y2, //端点2的y坐标
* CGFloat radius //半径
* )
*/
// 1/4 弧度*4 划出一个圆形
CGContextMoveToPoint(contextRef, 100, 100);
CGContextAddArcToPoint(contextRef, 100, 50, 150, 50, 50);
CGContextAddArcToPoint(contextRef, 200, 50, 200, 100, 50);
CGContextAddArcToPoint(contextRef, 200, 150, 150, 150, 50);
CGContextAddArcToPoint(contextRef, 100, 150, 100, 100, 50);
CGContextStrokePath(contextRef);
// 贝塞尔曲线
CGContextSetStrokeColorWithColor(contextRef, [UIColor orangeColor].CGColor); // 画笔颜色
/** 三次曲线函数
* void CGContextAddCurveToPoint (
* CGContextRef c,
* CGFloat cp1x, //控制点1 x坐标
* CGFloat cp1y, //控制点1 y坐标
* CGFloat cp2x, //控制点2 x坐标
* CGFloat cp2y, //控制点2 y坐标
* CGFloat x, //直线的终点 x坐标
* CGFloat y //直线的终点 y坐标
* );
*/
CGContextMoveToPoint(contextRef, 100, 300);
CGContextAddCurveToPoint(contextRef, 100, 300, 200, 0, 200, 300);
CGContextStrokePath(contextRef);
//三次曲线可以画圆弧
CGContextMoveToPoint(contextRef, 200, 200);
CGContextAddCurveToPoint(contextRef, 200, 100, 300, 100, 300 ,100);
CGContextStrokePath(contextRef);
/** 二次曲线
* void CGContextAddQuadCurveToPoint (
* CGContextRef c,
* CGFloat cpx, //控制点 x坐标
* CGFloat cpy, //控制点 y坐标
* CGFloat x, //直线的终点 x坐标
* CGFloat y //直线的终点 y坐标
* );
*/
CGContextMoveToPoint(contextRef, 100, 100);
CGContextAddQuadCurveToPoint(contextRef, 200, 0, 300, 150);
CGContextStrokePath(contextRef);
}
4.画矩形,画椭圆,多边形
- (void)drawShape:(CGContextRef)contextRef
{
CGContextSetFillColorWithColor(contextRef, [UIColor blackColor].CGColor);
// 画椭圆,如果长宽相等就是圆
CGContextAddEllipseInRect(contextRef, CGRectMake(50, 250, 50, 100));
// 画矩形,长宽相等就是正方形
CGContextAddRect(contextRef, CGRectMake(150, 250, 50, 100));
// 画多边形,多边形是通过path完成的
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, &CGAffineTransformIdentity, 50, 350);
CGPathAddLineToPoint(path, &CGAffineTransformIdentity, 100, 350);
CGPathAddLineToPoint(path, &CGAffineTransformIdentity, 80, 400);
CGPathCloseSubpath(path);
CGContextAddPath(contextRef, path);
// 填充
CGContextFillPath(contextRef);
}
5. 画文字
- (void)drawText:(CGContextRef)contextRef
{
// 文字样式
UIFont *font = [UIFont systemFontOfSize:18];
NSDictionary *dict = @{NSFontAttributeName:font, NSForegroundColorAttributeName:[UIColor colorWithRed:0.167 green:0.752 blue:1.000 alpha:1.000]};
[@"荣耀归来" drawInRect:CGRectMake(100, 450, 100, 50) withAttributes:dict];
}
6.画图片
// 画图片
- (void)drawPicture:(CGContextRef)contextRef
{
UIImage *image = [UIImage imageNamed:@"17.png"];
[image drawInRect:CGRectMake(100, 500, 100, 150)]; // 在坐标系中画出图片
}