美文网首页
iOS - 用UIBezierPath介绍和实现简单的扇形下载进

iOS - 用UIBezierPath介绍和实现简单的扇形下载进

作者: ShIwEn9 | 来源:发表于2019-01-21 17:44 被阅读0次
    所写知识点来自《小码哥视频教程》

    吐槽:实习生太苦b

    相关知识点:

    • DrawRect方法的使用
    • 常见图形的绘制:线条、多边形、圆
    • 绘图状态的设置:文字颜色、线宽等
    • 图形上下文状态的保存和恢复(图形上下文栈)
    • 图片的裁剪
    • 截图
    一、简单介绍Quartz2D

    1. 什么是Quartz2D?
    Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统

    2. Quartz 2D能完成的工作
    绘制图形 : 线条\三角形\矩形\圆\弧等
    绘制文字
    绘制\生成图片(图像)
    读取\生成PDF
    截图\裁剪图片
    自定义UI控件
    ...

    二、Quartz2D实例

    只要是往View中画东西,必须得在- (void)drawRect:(CGRect)rect;方法中去写

    1. 基本路径绘制

    • DrawRect在程序中的调用顺序:
      viewWillAppear -> drawRect -> viewDidAppear
      即将显示和显示完毕之间
    - (void)drawRect:(CGRect)rect {
        NSLog(@"%s",__func__) ;
    }
    
    控制器中

    2. UIBezierPath对象相关的方法和属性

    • UIBezierPath创建的类方法
    // 创建基本路径
    + (instancetype)bezierPath;
    // 创建矩形路径
    + (instancetype)bezierPathWithRect:(CGRect)rect;
    // 创建椭圆路径
    + (instancetype)bezierPathWithOvalInRect:(CGRect)rect;
    // 创建圆角矩形
    + (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius; // rounds all corners with the same horizontal and vertical radius
    // 创建指定位置圆角的矩形路径
    + (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;
    // 创建弧线路径
    + (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;
    // 通过CGPath创建
    + (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;
    
    • UIBezierPath相关属性和方法
      • 属性
    // 与之对应的CGPath
    @property(nonatomic) CGPathRef CGPath;
    - (CGPathRef)CGPath NS_RETURNS_INNER_POINTER CF_RETURNS_NOT_RETAINED;
    // 是否为空
    @property(readonly,getter=isEmpty) BOOL empty;
    // 整个路径相对于原点的位置及宽高
    @property(nonatomic,readonly) CGRect bounds;
    // 当前画笔位置
    @property(nonatomic,readonly) CGPoint currentPoint;
    
    // 线宽
    @property(nonatomic) CGFloat lineWidth;
    
    // 终点类型
    @property(nonatomic) CGLineCap lineCapStyle; 
    typedef CF_ENUM(int32_t, CGLineCap) {
        kCGLineCapButt,
        kCGLineCapRound,
        kCGLineCapSquare
    };
    
    // 交叉点的类型
    @property(nonatomic) CGLineJoin lineJoinStyle; 
    typedef CF_ENUM(int32_t, CGLineJoin) {
        kCGLineJoinMiter,
        kCGLineJoinRound,
        kCGLineJoinBevel
    };
    
    // 两条线交汇处内角和外角之间的最大距离,需要交叉点类型为kCGLineJoinMiter是生效,最大限制为10
    @property(nonatomic) CGFloat miterLimit; 
    // 个人理解为绘线的精细程度,默认为0.6,数值越大,需要处理的时间越长
    @property(nonatomic) CGFloat flatness; 
    // 决定使用even-odd或者non-zero规则
    @property(nonatomic) BOOL usesEvenOddFillRule;  
    
    • 方法
    // 反方向绘制path
    - (UIBezierPath *)bezierPathByReversingPath;
    
    // 设置画笔起始点
    - (void)moveToPoint:(CGPoint)point;
    
    // 从当前点到指定点绘制直线
    - (void)addLineToPoint:(CGPoint)point;
    
    // 添加弧线
    - (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise NS_AVAILABLE_IOS(4_0);
    /* center弧线圆心坐标 radius弧线半径 startAngle弧线起始角度 endAngle弧线结束角度 clockwise是否顺时针绘制 */
    
    // 添加贝塞尔曲线
    - (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
    /* endPoint终点 controlPoint控制点 */
    - (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;
    /* endPoint终点 controlPoint1、controlPoint2控制点 */
    
    // 移除所有的点,删除所有的subPath
    - (void)removeAllPoints;
    
    // 将bezierPath添加到当前path
    - (void)appendPath:(UIBezierPath *)bezierPath;
    
    // 填充
    - (void)fill;
    
    // 路径绘制
    - (void)stroke;
    
    // 在这以后的图形绘制超出当前路径范围则不可见
    - (void)addClip;
    

    3. UIBezierPath的简单使用

    基本步骤:
    1.获取上下文 -> 2.描述路径 -> 3.添加路径到上下文 -> 4.把上下文的内容渲染到View的layer上

    • UIBezierPath绘制直线
    • 无论是开启上下文还是获取上下文都是以以UIGraphics开头
    • 图形上下文(Graphics Context):是一个CGContextRef类型的数据
    • 图形上下文的作用:
      保存绘图信息、绘图状态
      决定绘制的输出目标(绘制到什么地方去?)
      (输出目标可以是PDF文件、Bitmap或者显示器的窗口上)
    • 相同的一套绘图序列,指定不同的Graphics Context,就可将相同的图像绘制到不同的目标上
    • Quartz2D提供了以下几种类型的Graphics Context:
      Bitmap Graphics Context
      PDF Graphics Context
      Window Graphics Context
      Layer Graphics Context
      Printer Graphics Context
    实例展示:
    
    /**
     作用:专门用来绘图
     什么时候调用:当View显示时调用
     rect :代表当前控件的bounds
     */
    - (void)drawRect:(CGRect)rect {
        NSLog(@"%s",__func__) ;
        //在此方法中内部会自动创建一个跟View相关联的上下文
        //可以直接获取
        NSLog(@"%@",NSStringFromCGRect(rect)) ;
        //小技巧:无论是开启上下文还是获取上下文都是以UIGraphics开头
        //1.获取当前跟View相关联的上下文(画板 <- 比喻)
        CGContextRef ctx = UIGraphicsGetCurrentContext() ;
        //2.描述路径(画笔)
        UIBezierPath * path = [UIBezierPath bezierPath] ;
        //2.1设置起点(画笔的落点) 坐标的原点是以当前绘制View的左上角为(0,0)原点来参考.
        [path moveToPoint:CGPointMake(50, 50)] ;
        //2.2添加一根线到某个点,终点(画笔的收点)
        [path addLineToPoint:CGPointMake(50, 250)] ;
        
        //一个路径可以描述多条线
        //再画另外一个点
        [path moveToPoint:CGPointMake(0, 0)] ; //起点
        [path addLineToPoint:CGPointMake(50, 30)] ;//终点
        
        //上一个路径的终点直接设为上一个路径的起点(x相同)
        [path addLineToPoint:CGPointMake(50,70)]; //终点x和起点x相同
        
        [path addLineToPoint:CGPointMake(30,70)]; //终点y和起点y相同
        
        //设置上下文的状态
        CGContextSetLineWidth(ctx, 5) ; // 设置线条的宽度
        //设置上下文的链接样式
        /*
         typedef CF_ENUM(int32_t, CGLineJoin) {
         kCGLineJoinMiter,默认样式
         kCGLineJoinRound,圆弧样式
         kCGLineJoinBevel,切去尖角样式
         };
         */
        CGContextSetLineJoin(ctx, kCGLineJoinRound) ;
        
        //设置顶角样式
        /*
         typedef CF_ENUM(int32_t, CGLineCap) {
         kCGLineCapButt,
         kCGLineCapRound,
         kCGLineCapSquare
         };
         */
        CGContextSetLineCap(ctx, kCGLineCapButt) ;
        
        //设置线的颜色  setStroke setFill 直接使用set,会自动匹配渲染的模式
        //[[UIColor redColor] setStroke] ;//描边
        //[[UIColor redColor] setFill] ; //填充
        [[UIColor redColor] set] ;
        
        //3.把路径添加到上下文
        CGContextAddPath(ctx, path.CGPath) ;
        
        //4.把上下文的内容渲染到View相关联的layer上(将画板添加到View)
        //渲染的上市有两种:
        //1.描边:stroke
        //2.填充:fill
        CGContextStrokePath(ctx) ;
        
    }
    
    效果展示
    • UIBezierPath绘制曲线

    画曲线,一般是一条直线,然后定义几个控制点,使直线变弯曲。

    二次曲线函数
    三次曲线函数
    - (void)drawRect:(CGRect)rect {
        //1.获取上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext() ;
        //2.描述路径
        UIBezierPath *path = [UIBezierPath bezierPath] ;
        //画笔起点
        [path moveToPoint:CGPointMake(20, 30)] ;
        //添加一条曲线到某个点上
        //参数一:终点
        //参数二:控制点
        [path addQuadCurveToPoint:CGPointMake(200, 30) controlPoint:CGPointMake(100, 100)] ;
        //3.把路径添加到上下文
        CGContextAddPath(ctx, path.CGPath) ;
        //4.把上下文的内容渲染到View的layer
        CGContextStrokePath(ctx) ;
    }
    
    效果
    • UIBezierPath绘制矩形
      bezierPathWithRect:描述矩形
      cornerRadius:可以理解成矩形最上方一个点到矩形左边顶点的距离。
    - (void)drawRect:(CGRect)rect {
        //获取上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext() ;
        //描述矩形路径
        /*
         bezierPathWithRect:描述矩形
         参数:矩形的w尺寸大小
         */
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 200, 100)] ;
        
        /*
         bezierPathWithRect:描述圆角矩形
         参数一:矩形的尺寸大小
         参数二:矩形的圆角半径
         */
        path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 200, 100) cornerRadius:15.f] ;
        
        //设置上下文的状态得要在渲染之前设置
        [[UIColor redColor] set] ;
        
        //把路径添加到上下文
        CGContextAddPath(ctx, path.CGPath) ;
        //把上下文的内容渲染到View的layer上
    //    CGContextStrokePath(ctx) ;//描边
        CGContextFillPath(ctx) ;
    }
    
    矩形效果
    • UIBezierPath绘制圆

    描述圆的画法有很多
    bezierPathWithOvalInRect:绘制圆

    - (void)drawRect:(CGRect)rect {
        //1.获取上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext() ;
        //2.描述绘画路径 bezierPathWithOvalInRect:绘制圆
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 100, 200)] ;
        //当宽度和高度一样的时候就是正圆了
        path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 100, 100)] ;
        //3.把路径添加到上下文
        CGContextAddPath(ctx, path.CGPath) ;
        
        //设置上下文
        [[UIColor magentaColor] set] ;
        
        //4.把上下文的内容渲染到View的layer上
        CGContextFillPath(ctx) ;
    }
    
    • 补充:快捷方法 - 其他图形也适用

    - (void)drawRect:(CGRect)rect {
        //2.描述绘画路径 bezierPathWithOvalInRect:绘制圆
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 100, 200)] ;
        [[UIColor redColor]set] ;
        [path stroke] ;
    //    [path fill] ;
    }
    
    效果
    • UIBezierPath绘制扇形和圆弧
    - (void)drawRect:(CGRect)rect {    
        /**
         绘制圆弧
         Center: 中心点坐标
         radius:弧所在的半径
         startAngle:开始的角度 ; 0度是圆的最右侧,向上的度数为负的,向下的度数为正的
         endAngle:结束的角度
         clockwise:是顺时针还是逆时针  默认:顺时针
         */
        
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 100) radius:50 startAngle:0 endAngle:M_PI_2 clockwise:YES] ;
        //添加一根线到圆心,然后关闭路径就成了扇形
        [path addLineToPoint:CGPointMake(100, 100)];
        //关闭路径
        [path closePath] ;
        [path stroke] ;
        [path fill] ;//当使用填充时,会自动关闭路径
        
    }
    
    效果
    实例-绘制下载进度条
    目录结构

    ProgressView.h

    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface ProgressView : UIView
    @property(nonatomic,assign)CGFloat value ;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    

    ProgressView.m

    #import "ProgressView.h"
    
    @implementation ProgressView
    -(void)setValue:(CGFloat)value{
        _value = value ;
        //这样系统不会执行drawRect方法
        //[self drawRect:self.bounds] ;
        //当系统调用drawRect方法的时候,在drawRect会自动创建跟View相关的上下文
        //手动调用是没有效果的
        //通知系统,执行drawRect方法
        //setNeedsDisplay:重新绘制
        [self setNeedsDisplay] ;
    }
    
    - (void)drawRect:(CGRect)rect {
        NSLog(@"%@",NSStringFromCGRect(rect));
        // Drawing code
        //1.获取view相关联的上下文
        CGContextRef ctx = UIGraphicsGetCurrentContext() ;
        //2.描述路径
        CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5) ;
        NSLog(@"%@",NSStringFromCGPoint(center)) ;
        CGFloat radius = rect.size.height * 0.5 -20 ;
        NSLog(@"%f",radius) ;
        CGFloat startAngle = -M_PI_2 ;
        CGFloat endAngle = startAngle + self.value * M_PI * 2 ;
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES] ;
        
        [[UIColor blueColor] set] ;
        
        //关闭路径
        [path addLineToPoint:center];
        
        //3.把路径添加到上下文
        CGContextAddPath(ctx, path.CGPath) ;
        //4.把上下文的l内容渲染到View上
    //    CGContextStrokePath(ctx) ;
        CGContextFillPath(ctx) ;
        
    }
    
    @end
    

    ViewController.m

    #import "ViewController.h"
    #import "ProgressView.h"
    
    @interface ViewController ()
    @property (weak, nonatomic) IBOutlet ProgressView *progressView;
    
    @property (weak, nonatomic) IBOutlet UILabel *progressLabel;
    @property (weak, nonatomic) IBOutlet UISlider *progressSlider;
    
    @end
    
    @implementation ViewController
    - (IBAction)progressValueChange:(UISlider *)sender {
        self.progressView.value = sender.value ;
        NSString *strValue = [NSString stringWithFormat:@"%.2f%%",sender.value * 100] ;
        self.progressLabel.text = strValue ;
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
    }
    @end
    
    屏幕快照 2019-01-22 11.48.38.png
    相关图片参考网络

    这样简单的使用Quartz2D就完成了,希望能够一起进步,共勉❤️。

    求职广告:本人实习生,现在急需一份工作,杭州南京合肥的都可以。对我感兴趣的可以私聊我 0.0。谢谢~~~

    相关文章

      网友评论

          本文标题:iOS - 用UIBezierPath介绍和实现简单的扇形下载进

          本文链接:https://www.haomeiwen.com/subject/gqecjqtx.html