iOS 手动画弧形进度条

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


IMG_0002.GIF

.h文件

#import 
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://upload-images.jianshu.io/upload_images/3552412-02477921addc85d9.GIF?imageMogr2/auto-orient/strip

你可能感兴趣的:(iOS 手动画弧形进度条)