美文网首页iOS开发你需要知道的
iOS 手动画弧形进度条

iOS 手动画弧形进度条

作者: 画舫烟中浅 | 来源:发表于2020-08-28 16:40 被阅读0次

    项目中需要一个可以拖动的弧形进度条,整了半天实现了该功能,现在记录一下。


    IMG_0002.GIF

    .h文件

    #import <UIKit/UIKit.h>
    NS_ASSUME_NONNULL_BEGIN
    
     @interface YHCircleSlider : UIControl
     @property (nonatomic,assign) int lineWidth;
     @property (nonatomic,setter=changeAngle:) int angle;
    
     @end
    
     NS_ASSUME_NONNULL_END
    

    .m文件

     #import "YHCircleSlider.h"
    
     #define ToRad(deg)         ( (M_PI * (deg)) / 180.0 )
     #define ToDeg(rad)        ( (180.0 * (rad)) / M_PI )
     #define SQR(x)            ( (x) * (x) )
    
    @implementation YHCircleSlider {
    
       CGFloat radius;
    
    }
    
    
     -(id)initWithFrame:(CGRect)frame{
       if ([super initWithFrame:frame]) {
        _lineWidth = 20;
        _angle = 280;
        radius = self.frame.size.width/2 -_lineWidth;
        //        radius = 125;
        self.backgroundColor = [UIColor clearColor];
       }
           return self;
    }
    
      - (void)drawRect:(CGRect)rect {
        [super drawRect:rect];
        CGContextRef context = UIGraphicsGetCurrentContext();
    
    //1.绘制灰色的背景
      CGContextAddArc(context, self.frame.size.width/2, self.frame.size.width/2, radius, -M_PI_2, M_PI*2, 0);
      [[UIColor colorWithRed:204/255.0 green:204/255.0 blue:205/255.0 alpha:1.0] setStroke];
      CGContextSetLineWidth(context, _lineWidth);
      CGContextSetLineCap(context, kCGLineCapButt);
      CGContextDrawPath(context, kCGPathStroke);
    
    //2.绘制进度
      CGContextAddArc(context, self.frame.size.width/2, self.frame.size.width/2,radius,-M_PI_2, ToRad(_angle), 0);
      [[UIColor colorWithRed:255.0/255 green:73.0/255 blue:73.0/255 alpha:1.0] setStroke];
      CGContextSetLineWidth(context, _lineWidth);
      CGContextSetLineCap(context, kCGLineCapRound);
      CGContextDrawPath(context, kCGPathStroke);
    
    //3.绘制拖动小块
      CGPoint handleCenter =  [self pointFromAngle: (self.angle)];
     // CGContextSetShadowWithColor(context, CGSizeMake(0, 0), 3,[UIColor blueColor].CGColor);
      [[UIColor colorWithRed:241/255.0 green:241/255.0 blue:241/255.0 alpha:1.0] setStroke];
      CGContextSetLineWidth(context, _lineWidth*0.35);
      CGContextAddEllipseInRect(context, CGRectMake(handleCenter.x, handleCenter.y, _lineWidth*0.35, _lineWidth*0.35));
      CGContextDrawPath(context, kCGPathStroke);
    }
    
     -(CGPoint)pointFromAngle:(int)angleInt{
       //中心点
       CGPoint centerPoint = CGPointMake(self.frame.size.width/2, self.frame.size.width/2 );
    
       //项目需求改一下滑块的坐标
       CGFloat pointXY = 0;
       if (0 <= angleInt && angleInt <45) {
           pointXY = -2.5;
       }else if (angleInt >= 45  && angleInt <= 90){
           pointXY = -2.5;
       }else if (angleInt >90   && angleInt <= 135){
           if (angleInt<112.5) {
              pointXY=-2.5;
         }else{
            pointXY=-1.0;
        }
       }else if (angleInt > 135  && angleInt <= 180){
           pointXY = -1.0;
       }else if (angleInt > 180  && angleInt < 270){
          pointXY = -3.0;
      }else if (angleInt>=270 && angleInt < 360){
          pointXY = -2.0;
      }
    
       //根据角度得到圆环上的坐标
      CGPoint result;
      result.y = round(centerPoint.y + radius * sin(ToRad(angleInt))) + pointXY;
      result.x = round(centerPoint.x + radius * cos(ToRad(angleInt))) + pointXY;
      return result;
     }
    
    -(BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
       [super beginTrackingWithTouch:touch withEvent:event];
       return YES;
     }
    
    
     -(BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
         [super continueTrackingWithTouch:touch withEvent:event];
         //获取触摸点
         CGPoint lastPoint = [touch locationInView:self];
         //使用触摸点来移动小块
        [self movehandle:lastPoint];
         //发送值改变事件
        [self sendActionsForControlEvents:UIControlEventValueChanged];
        return YES;
     }
    
    -(void)movehandle:(CGPoint)lastPoint{
    
      //获得中心点
       CGPoint centerPoint = CGPointMake(self.frame.size.width/2,
                                      self.frame.size.width/2);
    
      //计算中心点到任意点的角度
       float currentAngle = AngleFromNorth(centerPoint,
                                        lastPoint,
                                        NO);
      if (currentAngle>=270) {
         currentAngle = currentAngle-360;
       }
       int angleInt = floor(currentAngle);
    
       //保存新角度
       self.angle = angleInt;
    
       //重新绘制
       [self setNeedsDisplay];
    }
    
     -(void)changeAngle:(int)angle{
       _angle = angle;
       [self sendActionsForControlEvents:UIControlEventValueChanged];
       [self setNeedsDisplay];
    }
    
    //从苹果示例代码clockControl中拿来的函数
    //计算中心点到任意点的角度
    static inline float AngleFromNorth(CGPoint p1, CGPoint p2, BOOL flipped) {
    CGPoint v = CGPointMake(p2.x-p1.x,p2.y-p1.y);
    float vmag = sqrt(SQR(v.x) + SQR(v.y)), result = 0;
    v.x /= vmag;
    v.y /= vmag;
    double radians = atan2(v.y,v.x);
    result = ToDeg(radians);
    return (result >=0  ? result : result + 360.0);
    }
    
    @end
    

    用法

       YHCircleSlider *slider = [[YHCircleSlider alloc] initWithFrame:CGRectMake(0, 200, 300, 300)];
         slider.center = self.view.center;
         [slider addTarget:self action:@selector(newValue:) forControlEvents:UIControlEventValueChanged];
         [slider changeAngle:-90];
         [self.view addSubview:slider];
    

    图片地址:
    https://img.haomeiwen.com/i3552412/02477921addc85d9.GIF?imageMogr2/auto-orient/strip

    相关文章

      网友评论

        本文标题:iOS 手动画弧形进度条

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