• 利用贝塞尔曲线绘制(UIBezierPath)自定义iOS动态速度表,可以自定义刻度,刻度值,进度条样式


    GitHubDemo下载地址

    使用UIBezierPath画图步骤:

    1. 创建一个UIBezierPath对象
    2. 调用-moveToPoint:设置初始线段的起点
    3. 添加线或者曲线去定义一个或者多个子路径

    改变UIBezierPath对象跟绘图相关的属性。如,我们可以设置画笔的属性、填充样式等

    UIBezierPath创建方法介绍

    我们先看看UIBezierPath类提供了哪些创建方式,这些都是工厂方法,直接使用即可。

    + (instancetype)bezierPath;
    + (instancetype)bezierPathWithRect:(CGRect)rect;
    + (instancetype)bezierPathWithOvalInRect:(CGRect)rect;
    + (instancetype)bezierPathWithRoundedRect:(CGRect)rect
                                 cornerRadius:(CGFloat)cornerRadius;
    + (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;
    + (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;

    本文主要是利用下面的方法绘制圆形,进而形成动态的速度表盘形式:

    + (instancetype)bezierPathWithArcCenter:(CGPoint)center
                                     radius:(CGFloat)radius
                                 startAngle:(CGFloat)startAngle
                                   endAngle:(CGFloat)endAngle
                                  clockwise:(BOOL)clockwise;

    这个工厂方法用于画弧,参数说明如下:

    1. center: 弧线中心点的坐标
    2. radius: 弧线所在圆的半径
    3. startAngle: 弧线开始的角度值
    4. endAngle: 弧线结束的角度值
    5. clockwise: 是否顺时针画弧线
    UIBezierPath* outArc=[UIBezierPath bezierPathWithArcCenter:LuCenter radius:self.arcRadius startAngle:startAngle endAngle:endAngle clockwise:YES];
        CAShapeLayer* shapeLayer=[CAShapeLayer layer];
        shapeLayer.lineWidth=lineWitdth;
        shapeLayer.fillColor=filleColor.CGColor;
        shapeLayer.strokeColor=strokeColor.CGColor;
        shapeLayer.path=outArc.CGPath;
        shapeLayer.lineCap=kCALineCapRound;
        [self.layer addSublayer:shapeLayer];

    CAShapeLayer有着几点很重要(使用CAShapeLayer与UIBezierPath可以实现不在view的drawRect方法中就画出一些想要的图形):

      1. 它依附于一个给定的path,必须给与path,而且,即使path不完整也会自动首尾相接

      2. strokeStart以及strokeEnd代表着在这个path中所占用的百分比

      3. CAShapeLayer动画仅仅限于沿着边缘的动画效果,它实现不了填充效果

     下面介绍一下速度表盘的实现过程:

    1. 画外围弧度
      /**
       *  画弧度
       *
       *  @param startAngle  开始角度
       *  @param endAngle    结束角度
       *  @param lineWitdth  线宽
       *  @param filleColor  扇形填充颜色
       *  @param strokeColor 弧线颜色
       */
      -(void)drawArcWithStartAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle lineWidth:(CGFloat)lineWitdth fillColor:(UIColor*)filleColor strokeColor:(UIColor*)strokeColor{
          //保存弧线宽度,开始角度,结束角度
          self.lineWidth=lineWitdth;
          self.startAngle=startAngle;
          self.endAngle=endAngle;
          self.arcAngle=endAngle-startAngle;
          self.arcRadius=Calculate_radius;
          self.scaleRadius=self.arcRadius-self.lineWidth;
          self.scaleValueRadius=self.scaleRadius-self.lineWidth;
          self.speedLabel.text=@"0%";
          
          
          UIBezierPath* outArc=[UIBezierPath bezierPathWithArcCenter:LuCenter radius:self.arcRadius startAngle:startAngle endAngle:endAngle clockwise:YES];
          CAShapeLayer* shapeLayer=[CAShapeLayer layer];
          shapeLayer.lineWidth=lineWitdth;
          shapeLayer.fillColor=filleColor.CGColor;
          shapeLayer.strokeColor=strokeColor.CGColor;
          shapeLayer.path=outArc.CGPath;
          shapeLayer.lineCap=kCALineCapRound;
          [self.layer addSublayer:shapeLayer];
      }
    2. 绘制刻度,可以实现任意等分
      /**
       *  画刻度
       *
       *  @param divide      刻度几等分
       *  @param remainder   刻度数
       *  @param strokeColor 轮廓填充颜色
       *  @param fillColor   刻度颜色
       */
      -(void)drawScaleWithDivide:(int)divide andRemainder:(NSInteger)remainder strokeColor:(UIColor*)strokeColor filleColor:(UIColor*)fillColor scaleLineNormalWidth:(CGFloat)scaleLineNormalWidth scaleLineBigWidth:(CGFloat)scaleLineBigWidth{
          
          CGFloat perAngle=self.arcAngle/divide;
          //我们需要计算出每段弧线的起始角度和结束角度
          //这里我们从- M_PI 开始,我们需要理解与明白的是我们画的弧线与内侧弧线是同一个圆心
          for (NSInteger i = 0; i<= divide; i++) {
              
              CGFloat startAngel = (self.startAngle+ perAngle * i);
              CGFloat endAngel   = startAngel + perAngle/5;
              
              UIBezierPath *tickPath = [UIBezierPath bezierPathWithArcCenter:LuCenter radius:self.scaleRadius startAngle:startAngel endAngle:endAngel clockwise:YES];
              CAShapeLayer *perLayer = [CAShapeLayer layer];
              
              if((remainder!=0)&&(i % remainder) == 0) {
                  perLayer.strokeColor = strokeColor.CGColor;
                  perLayer.lineWidth   = scaleLineBigWidth;
                  
              }else{
                  perLayer.strokeColor = strokeColor.CGColor;;
                  perLayer.lineWidth   = scaleLineNormalWidth;
                  
              }
              
              perLayer.path = tickPath.CGPath;
              [self.layer addSublayer:perLayer];
              
          }
      }
    3. 绘制刻度值,刻度值可以按照任意数值等分
      /**
       *  画刻度值,逆时针设定label的值,将整个仪表切分为N份,每次递增仪表盘弧度的N分之1
       *
       *  @param divide 刻度值几等分
       */
      -(void)DrawScaleValueWithDivide:(NSInteger)divide{
          CGFloat textAngel =self.arcAngle/divide;
          if (divide==0) {
              return;
          }
          for (NSUInteger i = 0; i <= divide; i++) {
              CGPoint point = [self calculateTextPositonWithArcCenter:LuCenter Angle:-(self.endAngle-textAngel*i)];
              NSString *tickText = [NSString stringWithFormat:@"%ld%%",(divide - i)*100/divide];
              //默认label的大小23 * 14
              UILabel *text = [[UILabel alloc] initWithFrame:CGRectMake(point.x - 8, point.y - 7, 30, 14)];
              text.text = tickText;
              text.font = [UIFont systemFontOfSize:10.f];
              text.textColor = [UIColor redColor];
              text.textAlignment = NSTextAlignmentLeft;
              [self addSubview:text];
          }
      }
      //默认计算半径-10,计算label的坐标
      - (CGPoint)calculateTextPositonWithArcCenter:(CGPoint)center
                                             Angle:(CGFloat)angel
      {
          CGFloat x = (self.scaleValueRadius+3*self.lineWidth)* cosf(angel);
          CGFloat y = (self.scaleValueRadius+3*self.lineWidth)* sinf(angel);
          return CGPointMake(center.x + x, center.y - y);
      }
    4. 进度条曲线
      /**
       *  进度条曲线
       *
       *  @param fillColor   填充颜色
       *  @param strokeColor 轮廓颜色
       */
      - (void)drawProgressCicrleWithfillColor:(UIColor*)fillColor strokeColor:(UIColor*)strokeColor{
          UIBezierPath *progressPath  = [UIBezierPath bezierPathWithArcCenter:LuCenter radius:self.arcRadius startAngle:self.startAngle endAngle:self.endAngle clockwise:YES];
          CAShapeLayer *progressLayer = [CAShapeLayer layer];
          self.progressLayer = progressLayer;
          progressLayer.lineWidth = self.lineWidth+0.25f;
          progressLayer.fillColor = fillColor.CGColor;
          progressLayer.strokeColor = strokeColor.CGColor;
          progressLayer.path = progressPath.CGPath;
          progressLayer.strokeStart = 0;
          progressLayer.strokeEnd = 0.0;
          progressLayer.lineCap=kCALineCapRound;
          [self.layer addSublayer:progressLayer];
      }
    5. 为进度条添加渐变图层,图层颜色是从左向右渐变
      /**
       *  添加渐变图层
       *
       *  @param colorGradArray 颜色数组,如果想达到红-黄-红效果,数组应该是红,黄,红
       */
      -(void)setColorGrad:(NSArray*)colorGradArray{
          //渐变图层
          CALayer *gradientLayer = [CALayer layer];
          CAGradientLayer *gradientLayer1 =  [CAGradientLayer layer];
          //增加渐变图层,frame为当前layer的frame
          gradientLayer1.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
          [gradientLayer1 setColors:colorGradArray];
          [gradientLayer1 setStartPoint:CGPointMake(0, 1)];
          [gradientLayer1 setEndPoint:CGPointMake(1, 1)];
          [gradientLayer addSublayer:gradientLayer1];
          
          [gradientLayer setMask:_progressLayer]; //用progressLayer来截取渐变层
          [self.layer addSublayer:gradientLayer];
      }

      个人写代码喜欢添加注释,可是在奈何文笔不行,表达不清,请移步到我的GitHub上下载Demo,如果有什么问题也可以给我发邮件,评论探讨。

  • 相关阅读:
    深入浅出MFC——MFC六大关键技术仿真(二)
    错误:Invalid action class configuration that references an unknown class named [XXX]的解决
    错误:java.lang.NoClassDefFoundError: com/project/common/exception/ServiceException 的解决
    SQL查询语句优化的实用方法
    ueditor表格边框没有颜色的解决
    ueditor显示内容末尾有多余标记的解决
    form表单中enctype属性作用
    springMVC中@RequestParam和@RequestBody注解的用法
    错误:This function has none of DETERMINISTIC... 的解决
    如何区分内存类型及查看内存的兼容性
  • 原文地址:https://www.cnblogs.com/luerniu/p/5808854.html
Copyright © 2020-2023  润新知