iOS 分值表盘

先来表盘效果:
gif录制的不怎样。


iOS 分值表盘_第1张图片
1.gif

为了实现上述的效果,我们首当其冲的是得了解的是贝塞尔曲线。

Bézier curve(贝塞尔曲线)是应用于二维图形应用程序的数学曲线.主要有起始点、终止点(也称锚点)、控制点这几个概念。通过调整控制点,贝塞尔曲线的形状会发生变化。

弧线的参考系:


iOS 分值表盘_第2张图片
image.png

分步骤实现效果:
1、画出内侧的圆弧


iOS 分值表盘_第3张图片
inside.png
  // 内弧线
- (void)drawInsideArc
{
     //主要解释一下各个参数的意思
     //center  中心点(可以理解为圆心)
     //radius  半径
     //startAngle 起始角度
    //endAngle  结束角度
    //clockwise  是否顺时针

    CGFloat perAngle = M_PI / 80;

   for (int i = 0; i< 81; i++) {
    
      CGFloat startAngel = (-M_PI + perAngle * i);
      CGFloat endAngel   = startAngel + perAngle/3;
    
      UIBezierPath *tickPath = [UIBezierPath bezierPathWithArcCenter:self.m_Center radius:INSIDE_RADIU startAngle:startAngel endAngle:endAngel clockwise:YES];
      CAShapeLayer *perLayer = [CAShapeLayer layer];
      perLayer.strokeColor = [UIColor lightGrayColor].CGColor;
      perLayer.lineWidth   = 1.f;
      perLayer.path = tickPath.CGPath;
      [self.layer addSublayer:perLayer];
   }
}


2、画外侧变色表盘及刻度

iOS 分值表盘_第4张图片
outside.png
- (void)drawOutsideBg
{
  CGFloat perAngle = M_PI / 50;
  //我们需要计算出每段弧线的起始角度和结束角度
  //这里我们从- M_PI 开始,我们需要理解与明白的是我们画的弧线与内侧弧线是同一个圆心
  for (int i = 0; i< 51; i++) {
    
      CGFloat startAngel = (-M_PI + perAngle * i);
      CGFloat endAngel   = startAngel + perAngle;
    
      UIBezierPath *tickPath = [UIBezierPath bezierPathWithArcCenter:self.m_Center radius:OUTSIDE_RADIU startAngle:startAngel endAngle:endAngel clockwise:YES];
      CAShapeLayer *perLayer = [CAShapeLayer layer];
      perLayer.lineWidth   = 30.f;
      perLayer.strokeColor = [self getBgColor:i].CGColor;
      if (i % 5 == 0) {
           [self drawOutsideScaleWithAngel:endAngel withData:i];
      }
    
      perLayer.path = tickPath.CGPath;
      [self.layer addSublayer:perLayer];
   }
}

// 获取渐变背景色
- (UIColor *)getBgColor:(NSInteger)value
{
   float one = (255 + 255) / 60;//(255+255)除以最大取值的三分之二
   int r=0,g=0,b=0;
  if (value < 30)//第一个三等分
  {
      r = 255;
      g = (int)(one * value);
  }
  else if (value >= 30 && value < 60)//第二个三等分
  {
      r =  255 - (int)((value - 30) * one);//val减最大取值的三分之一;
      g = 255;
  }
  else { g = 255; }//最后一个三等分
  return RGBA(r, g, b, 1.0);
}

// 外侧 刻度
- (void)drawOutsideScaleWithAngel:(CGFloat)textAngel withData:(int)index
{
   CGPoint point      = [self calculateTextPositonWithArcCenter:self.m_Center Angle:-textAngel];
   NSString *tickText = [NSString stringWithFormat:@"%d",index * 2];
   if (index % 10 == 0) {
       tickText = [NSString stringWithFormat:@"%d",index * 2 *10];
   }else{
       if (index == 5) {
           tickText = @"超低";
       }else if(index == 15){
           tickText = @"较低";
       }else if(index == 25){
           tickText = @"正常";
       }else if(index == 35){
           tickText = @"较高";
       }else if(index == 45){
           tickText = @"超高";
       }
   }

   //默认label的大小30 * 14
   UILabel *text      = [[UILabel alloc] initWithFrame:CGRectMake(point.x - 15, point.y - 8, 30, 14)];
   text.text          = tickText;
   text.font          = [UIFont systemFontOfSize:10];
   text.textColor     = [UIColor colorWithRed:0.54 green:0.78 blue:0.91 alpha:1.0];
   text.textAlignment = NSTextAlignmentCenter;
   [self addSubview:text];

}

//默认计算半径135
- (CGPoint)calculateTextPositonWithArcCenter:(CGPoint)center
                                   Angle:(CGFloat)angel
{
   CGFloat x = 135 * cosf(angel);
   CGFloat y = 135 * sinf(angel);

  return CGPointMake(center.x + x, center.y - y);
}

3、绘制外部分类分割线

iOS 分值表盘_第5张图片
outside_1.png
  // 外侧弧线分割
- (void)drawOutsideArc
{
   CGFloat perAngle = M_PI / 5;
   //我们需要计算出每段弧线的起始角度和结束角度
   //这里我们从- M_PI 开始,我们需要理解与明白的是我们画的弧线与内侧弧线是同一个圆心
   for (int i = 1; i< 5; i++) {
    
       CGFloat startAngel = (-M_PI + perAngle * i);
       CGFloat endAngel   = startAngel + perAngle/80;
    
       UIBezierPath *tickPath = [UIBezierPath bezierPathWithArcCenter:self.m_Center radius:OUTSIDE_RADIU startAngle:startAngel endAngle:endAngel clockwise:YES];
       CAShapeLayer *perLayer = [CAShapeLayer layer];
       perLayer.lineWidth   = 30.f;
       perLayer.strokeColor = [UIColor whiteColor].CGColor;
       perLayer.path = tickPath.CGPath;
       [self.layer addSublayer:perLayer];
   }
}

4、使用label方式添加表盘中央view

5、进度展示,包含进度区域及进度line

 // 绘制进度填充
 - (void)drawProgreeArc
 {
    UIBezierPath *progressPath  = [UIBezierPath bezierPathWithArcCenter:self.m_Center
                                                             radius:130
                                                         startAngle:- M_PI
                                                           endAngle:0
                                                          clockwise:YES];
   self.progressLayer = [CAShapeLayer layer];
   self.progressLayer.lineWidth     =  30.f;
   self.progressLayer.fillColor     = [UIColor clearColor].CGColor;
   self.progressLayer.strokeColor   =  RGBA(185,243,110,0.2).CGColor;
   self.progressLayer.path          = progressPath.CGPath;
   self.progressLayer.strokeStart   = 0;
   self.progressLayer.strokeEnd     = 0;
   [self.layer addSublayer:self.progressLayer];
}

// 绘制进度曲线

- (void)drawProgreeLineArc
 {
   UIBezierPath *progressPath  = [UIBezierPath bezierPathWithArcCenter:self.m_Center
                                                             radius:118
                                                         startAngle:- M_PI
                                                           endAngle:0
                                                          clockwise:YES];
   self.progessLineLayer = [CAShapeLayer layer];
   self.progessLineLayer.lineWidth     =  2.f;
   self.progessLineLayer.fillColor     = [UIColor clearColor].CGColor;
   self.progessLineLayer.strokeColor   =  RGBA(236,92,55,1).CGColor;
   self.progessLineLayer.path          = progressPath.CGPath;
   self.progessLineLayer.strokeStart   = 0;
   self.progessLineLayer.strokeEnd     = 0;
   [self.layer addSublayer:self.progessLineLayer];
}

6、提供接口设置评分值及时间

  - (void)setM_CreditNum:(NSString *)m_CreditNum
{
   _m_CreditNum = m_CreditNum;

  // 实现项目逻辑
  //  *****
          
   // 评分值在表盘中进度展示
    CGFloat endStoke = _m_CreditNum? _m_CreditNum.floatValue/1000:0;
    self.progressLayer.strokeEnd = endStoke;
    self.progessLineLayer.strokeEnd = endStoke;

   // 数字动画逻辑
      [self creditAnimationBegin:0 End:m_CreditNum.floatValue];
}

7、评分值递增动态展示

  // 数字动画
- (void)creditAnimationBegin:(int)begin End:(int)end{

   NSMutableDictionary *userinfo = [NSMutableDictionary dictionary];

   [userinfo setObject:@(begin) forKey:@"beginNumber"];
   [userinfo setObject:@(end) forKey:@"endNumber"];

   self.timer = [NSTimer scheduledTimerWithTimeInterval:1/20.0 target:self selector:@selector(changeNumberAnimation:) userInfo:userinfo repeats:YES];

 }

- (void)changeNumberAnimation:(NSTimer *)timer{

   int begin = [timer.userInfo[@"beginNumber"] floatValue];
   int end = [timer.userInfo[@"endNumber"] floatValue];
   int current = begin;
   current += 50;

   [timer.userInfo setObject:@(current) forKey:@"beginNumber"];
   if (current >= end) {
       current = end;
   }
   self.s_NumLabel.text = [NSString stringWithFormat:@"%d",current];

   if (current == end) {
    
      [timer invalidate];
      self.timer = nil;
   }
}

我们可以在外部通过设置评分值,即可实现上述评分表盘。

demo github地址:https://github.com/yinxiaoyan/Credit_Plate

待优化点:
1.填充动画
2.提供UI修改接口

非常感谢参考文档作者。

参考:https://www.jianshu.com/p/7655315620f7

你可能感兴趣的:(iOS 分值表盘)