Quartz2D-1

1.学习目标

1.什么是Quartz2D
2.Quartz2D能做什么
3.图形上下文是什么
4.图形上下文的作用
5.绘图顺序
6.绘图步骤
7.基本图形绘制
8.上下文矩阵操作
9.上下文栈操作
10.Quartz2D坐标系与UIKit坐标系
11.Quartz2D的实际应用

2.基本介绍

2.1Quartz2D是什么

Quartz2D是苹果官方的二维绘图引擎。
它是跨平台,纯C语言。
同时支持iOS和Mac OS X系统。
Quartz2D的API来自于Core Graphics框架.
数据类型 和 函数 基本都以 CG 作为前缀.
注意:
Quartz2D 是苹果公司官方的二维绘图引擎,同时支持iOS和Mac OS X 系统。
Cocos2D(Cocos2D-x,Cocos2D-iPhone,Cocos2D-HTML5等):Cocos2D是一个第三方开源的2D游戏框架。
做游戏的还有Sprite Kit(苹果官方出的做iOS游戏的框架).
一般3D游戏用unity3D.

2.2Quartz2D能做什么

1.绘制图形:线条\三角形\矩形\圆\圆弧等。
2.绘制文字
3.绘制\生成图片(图像)
4.读取\生成PDF
5.截图\剪切图片
6.自定义UI控件
等等…

2.3图形上下文是什么

图形上下文连接图形绘制和输出目标的中间介质。
是 CGContextRef 类型
我们可以把它看做是画板或者草稿纸。

2.4图形上下文作用

图形上下文记录了路径信息,路径的状态,输出目标。
  路径信息:各种各样的图形
  绘图状态:颜色,线宽,样式,旋转,平移,图片裁剪区域等.
  输出目标:绘制到什么地方去?UIView,图片,pdf,打印机等

2.5绘图顺序

先绘制的图形在下面,后绘制的图形在上面

2.6基本图形绘制演练步骤

1.自定义UIView
2.实现drawRect方法
  2.1.获得图形上下文
  2.2.绘制路径,并且将路径添加到上下文中
  2.3.渲染(将图形上下文中的路径绘制到对应的设备中)

解析:
1.获得图形上下文就是在准备一个草稿纸
2.绘制路径,并且将路径添加到上下文中 就是在草稿纸中绘制路径
3.渲染 就是 把草稿纸上的内容搬到输出目标上去,执行渲染后,上下文还在,但是上下文的路径就不在了。

2.7drawRect方法介绍

1.绘图代码为什么要写在 drawRect 方法中
  跟上下文相关,因为我们需要获得上下文,才能把图形绘制到界面上.
  在这个方法中才可以获得正确的上下文.

2.rect 参数的含义
  当前自定义View的bounds.

3.drawRect 什么时候调用
  是系统调用的.
  当View第一次显示的时候会调用
  当View重绘的时候会调用

4.如何重绘
  调用View对象的 setNeedsDisplay 方法 (全部刷新)
  调用View对象的 setNeedsDisplayInRect: 方法 ,参数表示需要重绘的区域  (部分刷新)

5.为什么不能手动调用 drawRect
  还是上下文的问题,手动调用的时候,可能拿不到上下文.

3.绘制基本图形--第一种方式 CGContext...

3.1绘制一条直线

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径,并将路径添加到上下文中.
    CGContextMoveToPoint(ctx, 100, 100); // 添加起点
    CGContextAddLineToPoint(ctx, 200, 200); // 添加终点
    //3.渲染
    CGContextStrokePath(ctx);
}

解析:
在生活中,我们在草稿纸中画画,第一需要草稿纸,第二需要笔,然后就是在哪里去画画。
CGContextMoveToPoint(ctx, 100, 100); 把笔移动到草稿纸的指定位置,注意:这个时候还没有开始绘制呢.
CGContextAddLineToPoint(ctx, 200, 200);意思是笔从(100,100)的位置绘制到(200,200)的位置.注意:笔并没有离开草稿纸.
CGContextStrokePath(ctx);注意:在执行渲染以后,上下文还在,但是上下文中的路径已经不在了.并且路径就绘制到Layer上去了。

3.2绘制两条未连接的线

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径,并将路径添加到上下文中.
    //2.1绘制第一条线
    CGContextMoveToPoint(ctx, 100, 100); // 添加起点
    CGContextAddLineToPoint(ctx, 200, 200); // 添加终点
    //2.2绘制第二条线
    CGContextMoveToPoint(ctx, 300, 200); // 添加起点
    CGContextAddLineToPoint(ctx, 100, 50); // 添加终点
    //3.渲染
    CGContextStrokePath(ctx);
}

解析:
CGContextMoveToPoint 方法 是把笔悬空草稿纸移动,移动过程中并不绘制路径.
注意:从相同点开始绘制,线肯定是可以连接起来的.

3.3绘制两条连接的线

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径,并将路径添加到上下文中.
    //2.1绘制第一条线
    CGContextMoveToPoint(ctx, 100, 100); // 添加起点
    CGContextAddLineToPoint(ctx, 200, 200); // 添加终点
    //2.2绘制第二条线
    CGContextAddLineToPoint(ctx, 300, 100); // 添加终点
    //3.渲染
    CGContextStrokePath(ctx);
}

解析: CGContextAddLineToPoint 会默认把上一条线的终点做为自己的起点.

3.4关闭路径

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径,并将路径添加到上下文中.
    //2.1绘制第一条线
    CGContextMoveToPoint(ctx, 100, 100); // 添加起点
    CGContextAddLineToPoint(ctx, 200, 200); // 添加终点
    //2.2绘制第二条线
    CGContextAddLineToPoint(ctx, 300, 100); // 添加终点
    //2.3关闭路径
    CGContextClosePath(ctx);
    //3.渲染
    CGContextStrokePath(ctx);
}

解析:
1.关闭路径是把最后一条线的终点和第一条线的起点连接起来
2.注意:第一条线是就近的CGContextMoveToPoint点
3.注意:如果CGContextMoveToPoint后面没有跟CGContextAddLineToPoint那么此点无效

3.5绘制矩形

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径,并将路径添加到上下文中.
    CGContextAddRect(ctx, CGRectMake(100, 100, 100, 100));
    //3.渲染
    CGContextStrokePath(ctx);
}

3.6绘制圆形\椭圆

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径,并将路径添加到上下文中.
    //注意:矩形为正方形呈现是图形就是圆,矩形为长方形呈现的图形就是椭圆
    CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100));
    //3.渲染
    CGContextStrokePath(ctx);
}

3.7绘制圆弧

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径,并将路径添加到上下文中.
    CGContextAddArc(ctx, rect.size.width*0.5, rect.size.height*0.5, 100, 0, M_PI_4, 0);
    //3.渲染
    CGContextStrokePath(ctx);
}
解析:
1. 0是顺时针,1是逆时针

3.8绘制扇形

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径,并将路径添加到上下文中.
    //2.1绘制圆弧
    CGContextAddArc(ctx, rect.size.width*0.5, rect.size.height*0.5, 100, 0, M_PI_4, 0);
    //2.2连接中心点
    CGContextAddLineToPoint(ctx,rect.size.width*0.5, rect.size.height*0.5);
    //2.3关闭路径
    CGContextClosePath(ctx);
    //3.渲染
    CGContextStrokePath(ctx);
}

4.绘制基本图形--第二种方式 CGMutablePathRef

4.1绘制一条直线

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, 100, 100);
    CGPathAddLineToPoint(path, NULL, 200, 200);
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path);
    //4.渲染
    CGContextStrokePath(ctx);
}

解析:
CGPathMoveToPoint(path, NULL, 100, 100); 添加起点,注意:这个点并没有在草稿纸上
CGPathAddLineToPoint(path, NULL, 200, 200);添加终点,这样会绘制一条路径,但是这条路径并没有在草稿纸上.
CGContextAddPath(ctx, path); 会把这个路径拷贝一份放到草稿纸中.

4.2绘制两条未连接的线

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    CGMutablePathRef path = CGPathCreateMutable();
    
    //2.1添加第一条线
    CGPathMoveToPoint(path, NULL, 100, 100);
    CGPathAddLineToPoint(path, NULL, 200, 200);
    
    //2.2添加第二条线
    CGPathMoveToPoint(path, NULL, 300 , 300);
    CGPathAddLineToPoint(path, NULL, 300, 100);
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path);
    //4.渲染
    CGContextStrokePath(ctx);
}

4.3绘制两条连接的线

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    CGMutablePathRef path = CGPathCreateMutable();
    
    //2.1添加第一条线
    CGPathMoveToPoint(path, NULL, 100, 100);
    CGPathAddLineToPoint(path, NULL, 200, 200);
    
    //2.2添加第二条线
    CGPathAddLineToPoint(path, NULL, 300, 100);
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path);
    //4.渲染
    CGContextStrokePath(ctx);
}

解析:
CGPathAddLineToPoint 会默认把上一条线的终点做为自己的起点.

4.4关闭路径

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, 100, 100);
    CGPathAddLineToPoint(path, NULL, 200, 200);
    CGPathAddLineToPoint(path, NULL, 300, 100);
    //关闭路径
    CGPathCloseSubpath(path);
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path);
    //4.渲染
    CGContextStrokePath(ctx);
}
解析:
1.关闭路径是把最后一条线的终点和第一条线的起点连接起来
2.注意:第一条线是就近的CGPathAddLineToPoint点
3.注意:如果 CGPathMoveToPoint 后面没有CGPathAddLineToPoint那么此点无效

4.5绘制矩形

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, CGRectMake(100, 100, 100, 100));
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path);
    //4.渲染
    CGContextStrokePath(ctx);
}

4.6绘制圆形\椭圆

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    CGMutablePathRef path = CGPathCreateMutable();
    //注意:矩形是正方形会绘制成圆,矩形是长方形会绘制成椭圆
    CGPathAddEllipseInRect(path, NULL, CGRectMake(100, 100, 100, 100));
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path);
    //4.渲染
    CGContextStrokePath(ctx);
}

4.7绘制圆弧

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddArc(path, NULL, rect.size.width*0.5, rect.size.height*0.5, 100, 0, M_PI_4, 0);
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path);
    //4.渲染
    CGContextStrokePath(ctx);
}
解析:
1. 0是顺时针,1是逆时针

4.8绘制扇形

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    CGMutablePathRef path = CGPathCreateMutable();
    //2.1绘制圆弧
    CGPathAddArc(path, NULL, rect.size.width*0.5, rect.size.height*0.5, 100, 0, M_PI_4, 0);
    //2.2连接中心点
    CGPathAddLineToPoint(path, NULL,rect.size.width*0.5, rect.size.height*0.5);
    //2.3关闭路径
    CGPathCloseSubpath(path);
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path);
    //4.渲染
    CGContextStrokePath(ctx);
}

5.绘制基本图形--第三种方式 UIBezierPath

5.1绘制一条直线

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(100, 100)];
    [path addLineToPoint:CGPointMake(200, 200)];
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path.CGPath);
    //4.渲染
    CGContextStrokePath(ctx);
}

解析:
moveToPoint 添加起点,注意:这个点并没有在草稿纸上
addLineToPoint添加终点,这样会绘制一条路径,但是这条路径并没有在草稿纸上.
CGContextAddPath 会把这个路径拷贝一份放到草稿纸中.

5.2绘制两条未连接的线

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    //2.1 添加第一条线
    [path moveToPoint:CGPointMake(100, 100)];
    [path addLineToPoint:CGPointMake(200, 200)];
    
    //2.1 添加第二条线
    [path moveToPoint:CGPointMake(300, 200)];
    [path addLineToPoint:CGPointMake(400, 100)];
    
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path.CGPath);
    //4.渲染
    CGContextStrokePath(ctx);
}

5.3绘制两条连接的线

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    //2.1 添加第一条线
    [path moveToPoint:CGPointMake(100, 100)];
    [path addLineToPoint:CGPointMake(200, 200)];
    
    //2.1 添加第二条线
    [path addLineToPoint:CGPointMake(300, 100)];
    
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path.CGPath);
    //4.渲染
    CGContextStrokePath(ctx);
}

5.4特有的绘制方式

- (void)drawRect:(CGRect)rect {
    //1.绘制路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    //2.添加第一条线
    [path moveToPoint:CGPointMake(100, 100)];
    [path addLineToPoint:CGPointMake(200, 200)];
    //3.渲染
    [path stroke];
}

解析:
渲染方法会默认将路径添加到当前上下文.

5.5关闭路径

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    //2.1添加第一条线
    [path moveToPoint:CGPointMake(100, 100)];
    [path addLineToPoint:CGPointMake(200, 200)];
    //2.2添加第二条线
    [path addLineToPoint:CGPointMake(300, 100)];
    //2.3关闭路径
    [path closePath];
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path.CGPath);
    //4.渲染
    CGContextStrokePath(ctx);
}
注意:
1. 关闭路径是把最后一条线的终点和第一条线的起点连接起来
2.注意:第一条线是就近的moveToPoint点
3.如果moveToPoint后没有响应的addLineToPoint方法,那么这个点无效

5.6绘制矩形

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(100, 100, 100, 100)];
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path.CGPath);
    //4.渲染
    CGContextStrokePath(ctx);
}

5.7绘制圆形\椭圆

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    //注意:矩形是正方形会绘制成圆,矩形是长方形会绘制成椭圆
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 100, 100)];
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path.CGPath);
    //4.渲染
    CGContextStrokePath(ctx);
}

5.8绘制圆弧

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(rect.size.width*0.5, rect.size.height*0.5) radius:100 startAngle:0 endAngle:M_PI_4 clockwise:YES];
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path.CGPath);
    //4.渲染
    CGContextStrokePath(ctx);
}
解析:
1. YES是顺时针,NO是逆时针

5.9绘制扇形

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    //2.1创建圆弧
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(rect.size.width*0.5, rect.size.height*0.5) radius:100 startAngle:0 endAngle:M_PI_4 clockwise:YES];
    //2.2连接中心点
    [path addLineToPoint:CGPointMake(rect.size.width*0.5, rect.size.height*0.5)];
    //2.3关闭路径
    [path closePath];
    //3将路径添加到上下文中
    CGContextAddPath(ctx, path.CGPath);
    //4.渲染
    CGContextStrokePath(ctx);
}

6.绘图属性设置

6.1颜色设置

//第一种方式:OC设置方式
/*
 setStroke 描边颜色
 setFill 填充色
 set 既设置描边又设置填充色
 */
[[UIColor redColor] setFill];

//第二种方式:C设置方式
//2.1设置边框颜色
CGContextSetRGBStrokeColor(ctx, 100/255.0, 100/255.0, 100/255.0, 1.0);
//2.2设置填充色
CGContextSetRGBFillColor(ctx, 100/255.0, 100/255.0, 100/255.0, 1.0);

注意:
1.在同时设置了边框和填充色时,只有采用 既填充又边框 的渲染方式才能显示两种颜色
2.一定要在渲染之前设置
3.设置颜色就近原则,也就是在渲染之前多处设置颜色.

6.2线宽设置

CGContextSetLineWidth(ctx, 5);

6.3首尾样式

/*
 kCGLineCapButt 默认,直角
 kCGLineCapRound 圆角
 kCGLineCapSquare 方形,与第一个的区别就是长了一点(左右两边各加5的距离)
 */
CGContextSetLineCap(ctx, kCGLineCapRound);


//UIBezierPath 封装的首尾样式
[path setLineCapStyle:kCGLineCapRound];

6.4拼接样式

/*
 kCGLineJoinMiter 默认,直角
 kCGLineJoinRound 圆角
 kCGLineJoinBevel 切角
 */
CGContextSetLineJoin(ctx, kCGLineJoinRound);

//UIBezierPath 封装的拼接样式
[path setLineJoinStyle:kCGLineJoinRound];

7.渲染

7.1渲染方式

//填充式渲染
CGContextFillPath(ctx);
//边框式渲染
CGContextStrokePath(ctx);
/*
 kCGPathFill  填充式渲染
 kCGPathEOFill 奇偶填充渲染
 kCGPathStroke  描边式渲染
 kCGPathFillStroke  既填充又描边
 kCGPathEOFillStroke 奇偶填充描边渲染
 */
CGContextDrawPath(ctx, kCGPathFillStroke);

7.2奇偶填充规则

被覆盖过基数次的点填充,被覆盖过偶数次的点不填充

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 200, 300, 50)];
    CGContextAddPath(ctx, path.CGPath);
    
    UIBezierPath *path1 = [UIBezierPath bezierPathWithRect:CGRectMake(200, 100, 50, 300)];
    CGContextAddPath(ctx, path1.CGPath);
    //4.渲染
    CGContextDrawPath(ctx, kCGPathEOFill);
}

7.3非零环绕数规则 -- 了解,默认的填充规则

从左边跨过,+1.从右边跨过,-1.最后如果是0,那么不填充,否则填充。

- (void)drawRect:(CGRect)rect {
    //1.获得上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.绘制路径
    //顺时针大圆
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150) radius:100 startAngle:0 endAngle:M_PI*2 clockwise:1];
    CGContextAddPath(ctx, path.CGPath);
    //逆时针小圆
    UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150) radius:50 startAngle:0 endAngle:M_PI*2 clockwise:0];
    CGContextAddPath(ctx, path1.CGPath);
    //4.渲染
    CGContextDrawPath(ctx, kCGPathFill);
}

解析:
1.错误的,但是容易理解
没有路径时,默认都是0,假设在大圆上随便取一个点,大圆顺时针绘制,从右往左跨过-1。
然后绘制小圆,小圆是逆时针绘制,小圆从左往右跨过那个点+1.
所以,如果选的点在大圆内,小圆外就是-1
选的点在大圆内,也在小圆内,那么这点被从左往右跨过,也被从右往左跨过,那么就是0,不绘制。

2.正确的,不容易理解
在大圆内随便取一个点,然后往任意方向来一条射线(切线不要考虑),这条射线和路径是有交点的,就是我们在画圆的时候,经过这条射线是从右往左,还是从左往右。
当这条线只经过了大圆与小圆没有交点,那么大圆顺时针绘制,从右往左跨过-1.
当这条线即经过大圆也经过小圆,那么大圆顺时针绘制,从右往左跨过-1,小圆逆时针绘制,从左往右跨过+1,这样就有了0.

7.4OC的非零环绕数规则

- (void)drawRect:(CGRect)rect {
    // 注意:只要小圆是逆时针绘制就可以。
    //顺时针大圆
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150) radius:100 startAngle:0 endAngle:M_PI*2 clockwise:1];
    //逆时针小圆
    [path addArcWithCenter:CGPointMake(150, 150) radius:50 startAngle:0 endAngle:M_PI * 2 clockwise:1];
    //使用奇偶填充规则
    path.usesEvenOddFillRule = YES;
    //填充
    [path fill];
}

8.饼状图和柱状图

8.1饼状图

思路:
1.准备一个数据数组。相加可以是1,也可以是100.自己设计即可。我们假设是1
2.定义开始变量 和 结束变量都是0.
3.绘制扇形,下一个扇形的起始角度上之前所有扇形的角度总和。

- (void)drawRect:(CGRect)rect {
    //1.准备扇形块比例数组
    NSArray *array = @[@0.3,@0.1,@0.2,@0.4];
    //2.定义起始角度 和 结束角度
    CGFloat start = 0;
    CGFloat end = 0;
    for (int i = 0; i<array.count; i++) {
        //3.计算结束角度
        end = 2 * M_PI * [array[i] floatValue] + start;
        //4.绘制圆弧
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5) radius:100 startAngle:start endAngle:end clockwise:YES];
        //5.连接中心点
        [path addLineToPoint:CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5)];
        //6.设置随机颜色
        [[self randomColor] set];
        //7.填充绘制
        [path fill];
        //8.重置起始点
        start = end;
    }
}

8.2柱状图

思路:
1.准备数据数组
2.计算每个柱子的矩形位置--需要遍历数组
  宽度 = View的宽度 / (数组的长度 * 2 - 1);
  高度 = View的高度 * 当前柱子的比例
  X位置 = 宽度 * 当前柱子位置 * 2;
  Y位置 = View的高度 - 高度;
3.创建每个矩形并且填充.

- (void)drawRect:(CGRect)rect {
    //1.准备柱状图比例数组
    NSArray *array = @[@1,@0.5,@0.7,@0.3,@0.1,@0.6];
    //宽度 = 平均View的宽度
    CGFloat rectW = rect.size.width / (array.count*2-1);
    for (int i = 0; i < array.count; i++) {
        //高度 = View的高度的比例
        CGFloat rectH = rect.size.height * [array[i] floatValue];
        // X = 宽度 * 位置
        CGFloat rectX = rectW * i * 2;
        // Y = View的高度 - rect的高度
        CGFloat rectY = rect.size.height - rectH;
        //2.创建矩形
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(rectX, rectY, rectW, rectH)];
        //3.设置颜色
        [[self randomColor] set];
        //4.填充
        [path fill];
    }
}

8.3饼状图柱状图的封装

思路:
1.把数据的提供交给用户.
2.通过代理的方式来获得我们想要的数据.

9.进度条

思路:
1.自定义UIView
2.根据比例绘制圆弧
3.每当重新设置进度比例时,重绘界面
4.如果界面需要文字显示下载比例,就添加一个label.
- (void)drawRect:(CGRect)rect {
    //1.计算圆弧中心点
    CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5);
    //2.计算圆弧半径
    CGFloat radius = MIN(rect.size.width, rect.size.height);
    //3.计算结束角度
    CGFloat end = M_PI * 2 * self.progress;
    //4.绘制圆弧
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius*0.5 startAngle:0 endAngle:end clockwise:YES];
    //5.连接中心点
    [path addLineToPoint:CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5)];
    //6.填充
    [path fill];
    
}

- (void)setProgress:(CGFloat)progress{
    _progress = progress;
    //重绘界面
    [self setNeedsDisplay];
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容