// // CYCircularSlider.m // CYCircularSlider // // Created by user on 2018/3/23. // Copyright © 2018年 com. All rights reserved. // #import "CYCircularSlider.h" #define ToRad(deg) ( (M_PI * (deg)) / 180.0 ) //半圆弧度 #define ToDeg(rad) ( (180.0 * (rad)) / M_PI ) #define SQR(x) ( (x) * (x) ) @implementation CYCircularSlider{ int _angle; CGFloat radius; CGFloat _currentValue;// 档位 int _fixedAngle; } -(instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { CGFloat height = self.frame.size.height; _maximumValue = 10.0f; _minimumValue = 0.0f; _currentValue = 0.0f; _lineWidth = 5.0f; _unfilledColor = [UIColor colorWithRed:250/255.0f green:60/255.0f blue:20/255.0f alpha:1.0f]; _filledColor = [UIColor colorWithRed:175/255.0f green:195/255.0f blue:5/255.0f alpha:1.0f]; _handleColor = UIColor.whiteColor; _handleColor2 = RDSGreenColor; _handleColor3 = UIColor.clearColor; radius = self.frame.size.height/2 - _lineWidth/2-10;// 半径 决定大小 _angle = 140; self.backgroundColor = [UIColor clearColor]; } return self; } - (void)setLineWidth:(int)lineWidth{ _lineWidth = lineWidth; radius = self.frame.size.height/2 - _lineWidth/2-10;// 半径 决定大小 } #pragma mark 画圆 // CGContextAddArc(Context, CGFloat x , CGFloat y, CGFloat radius, CGFloat startAngle , CGFloat endAngle, int clockwise); // 关于角度,由x,y可确定圆心坐标,而0,0角度位于圆心的正下方。 // startAngle是由0,0偏移的。 // 偏移方向是由clockwise控制的,0为顺时针,1为逆时针。 -(void)drawRect:(CGRect)rect{ [super drawRect:rect]; CGFloat x = self.frame.size.width/2; CGFloat y = self.frame.size.height/2; //画固定的下层圆 CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextAddArc(ctx, x, y, radius, M_PI/180*140, M_PI/180*40, 0); [_unfilledColor setStroke]; CGContextSetLineWidth(ctx, _lineWidth); CGContextSetLineCap(ctx, kCGLineCapRound); CGContextDrawPath(ctx, kCGPathStroke); //画可滑动的上层圆 CGContextAddArc(ctx, x, y, radius, M_PI/180*140, M_PI/180*(_angle), 0); [_filledColor setStroke]; CGContextSetLineWidth(ctx, _lineWidth); CGContextSetLineCap(ctx, kCGLineCapRound); CGContextDrawPath(ctx, kCGPathStroke); // 画按钮 [self drawHandle:ctx]; } #pragma mark 画按钮 -(void)drawHandle:(CGContextRef)ctx{ CGContextSaveGState(ctx); // 阴影 UIColor *shadowColor = [UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:0.2000]; CGContextSaveGState(ctx); CGContextSetShadowWithColor(ctx, CGSizeMake(0,4.4), 11.1, shadowColor.CGColor); // 大圆点 CGPoint handleCenter = [self pointFromAngle: _angle]; [_handleColor set]; CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x-8, handleCenter.y-8, _lineWidth+16, _lineWidth+16)); CGContextRestoreGState(ctx); // 中间小圆点 CGFloat width = 18; CGContextSaveGState(ctx); [_handleColor2 set]; CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x-(width-_lineWidth)/2, handleCenter.y-(width-_lineWidth)/2, width, width)); CGContextRestoreGState(ctx); // 和线一样宽度的圆点,默认透明隐藏,设置了_handleColor3颜色才显示 CGContextSaveGState(ctx); [_handleColor3 set]; CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x, handleCenter.y, _lineWidth, _lineWidth)); CGContextRestoreGState(ctx); } -(CGPoint)pointFromAngle:(int)angleInt{ //Define the Circle center CGPoint centerPoint = CGPointMake(self.frame.size.width/2 - _lineWidth/2, self.frame.size.height/2 - _lineWidth/2); //Define The point position on the circumference CGPoint result; result.y = round(centerPoint.y + radius * sin(ToRad(angleInt))) ; result.x = round(centerPoint.x + radius * cos(ToRad(angleInt))); 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]; //用于排除点在圆外面点与圆心半径80以内的点 // if ((lastPoint.x>=0&&lastPoint.x<=275)&&(lastPoint.y>=0 && lastPoint.y<=275)) { // if ((lastPoint.x<=57.5 ||lastPoint.x>=217.5)||(lastPoint.y<=57.5 ||lastPoint.y>=217.5)) { [self moveHandle:lastPoint]; // } // } [self sendActionsForControlEvents:UIControlEventValueChanged]; return YES; } -(void)moveHandle:(CGPoint)point { CGPoint centerPoint = CGPointMake(self.frame.size.width/2, self.frame.size.height/2); int currentAngle = floor(AngleFromNorth(centerPoint, point, NO)); if (currentAngle>40 && currentAngle <140) { }else{ if (currentAngle<=40) { _angle = currentAngle+360; }else{ _angle = currentAngle; } } _currentValue =[self valueFromAngle]; [self setNeedsDisplay]; } 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); } //在这个地方调整进度条 -(float) valueFromAngle { CGFloat curValue = _currentValue; if(_angle <= 40) { curValue = 220+_angle; } else if(_angle>40 && _angle < 140){ }else{ curValue = _angle-100-40; } _fixedAngle = curValue; CGFloat value = (curValue*(_maximumValue - _minimumValue))/260.0f; // 四舍五入 档位 int a; a = (int)(value + 0.5); _angle = (int)260/(_maximumValue - _minimumValue)*a+140; if(a != _currentValue){ _currentValue = a;// 档位 _value = (int)(a+_minimumValue);// 用户设置的值 //DDLog(@"Value:%d",_value); [self.delegate senderVlueChangingWithNum:_value]; } return a; } -(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{ [super endTrackingWithTouch:touch withEvent:event]; [self.delegate senderVlueWithNum:_value]; } #pragma mark 设置进度条位置 - (void)setValue:(int)value{ _value = value; if(value > _maximumValue){ _currentValue = _maximumValue - _minimumValue; }else if (value < _minimumValue){ _currentValue = 0; }else{ _currentValue = value - _minimumValue; } _angle = (int)260/(_maximumValue - _minimumValue)*_currentValue+140; [self setNeedsDisplay]; } -(void)setAddAngel{ _angle += (int)260/(_maximumValue - _minimumValue); if (_angle>400) { _angle = 400; } [self setNeedsDisplay]; _currentValue =[self valueFromAngle]; } -(void)setMovAngel{ _angle -= (int)260/(_maximumValue - _minimumValue); if (_angle<140) { _angle = 140; } [self setNeedsDisplay]; _currentValue =[self valueFromAngle]; } @end