CYCircularSlider.m 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. //
  2. // CYCircularSlider.m
  3. // CYCircularSlider
  4. //
  5. // Created by user on 2018/3/23.
  6. // Copyright © 2018年 com. All rights reserved.
  7. //
  8. #import "CYCircularSlider.h"
  9. #define ToRad(deg) ( (M_PI * (deg)) / 180.0 ) //半圆弧度
  10. #define ToDeg(rad) ( (180.0 * (rad)) / M_PI )
  11. #define SQR(x) ( (x) * (x) )
  12. @implementation CYCircularSlider{
  13. int _angle;
  14. CGFloat radius;
  15. CGFloat _currentValue;// 档位
  16. int _fixedAngle;
  17. }
  18. -(instancetype)initWithFrame:(CGRect)frame{
  19. self = [super initWithFrame:frame];
  20. if (self) {
  21. CGFloat height = self.frame.size.height;
  22. _maximumValue = 10.0f;
  23. _minimumValue = 0.0f;
  24. _currentValue = 0.0f;
  25. _lineWidth = 5.0f;
  26. _unfilledColor = [UIColor colorWithRed:250/255.0f green:60/255.0f blue:20/255.0f alpha:1.0f];
  27. _filledColor = [UIColor colorWithRed:175/255.0f green:195/255.0f blue:5/255.0f alpha:1.0f];
  28. _handleColor = UIColor.whiteColor;
  29. _handleColor2 = RDSGreenColor;
  30. _handleColor3 = UIColor.clearColor;
  31. radius = self.frame.size.height/2 - _lineWidth/2-10;// 半径 决定大小
  32. _angle = 140;
  33. self.backgroundColor = [UIColor clearColor];
  34. }
  35. return self;
  36. }
  37. - (void)setLineWidth:(int)lineWidth{
  38. _lineWidth = lineWidth;
  39. radius = self.frame.size.height/2 - _lineWidth/2-10;// 半径 决定大小
  40. }
  41. #pragma mark 画圆
  42. // CGContextAddArc(Context, CGFloat x , CGFloat y, CGFloat radius, CGFloat startAngle , CGFloat endAngle, int clockwise);
  43. // 关于角度,由x,y可确定圆心坐标,而0,0角度位于圆心的正下方。
  44. // startAngle是由0,0偏移的。
  45. // 偏移方向是由clockwise控制的,0为顺时针,1为逆时针。
  46. -(void)drawRect:(CGRect)rect{
  47. [super drawRect:rect];
  48. CGFloat x = self.frame.size.width/2;
  49. CGFloat y = self.frame.size.height/2;
  50. //画固定的下层圆
  51. CGContextRef ctx = UIGraphicsGetCurrentContext();
  52. CGContextAddArc(ctx, x, y, radius, M_PI/180*140, M_PI/180*40, 0);
  53. [_unfilledColor setStroke];
  54. CGContextSetLineWidth(ctx, _lineWidth);
  55. CGContextSetLineCap(ctx, kCGLineCapRound);
  56. CGContextDrawPath(ctx, kCGPathStroke);
  57. //画可滑动的上层圆
  58. CGContextAddArc(ctx, x, y, radius, M_PI/180*140, M_PI/180*(_angle), 0);
  59. [_filledColor setStroke];
  60. CGContextSetLineWidth(ctx, _lineWidth);
  61. CGContextSetLineCap(ctx, kCGLineCapRound);
  62. CGContextDrawPath(ctx, kCGPathStroke);
  63. // 画按钮
  64. [self drawHandle:ctx];
  65. }
  66. #pragma mark 画按钮
  67. -(void)drawHandle:(CGContextRef)ctx{
  68. CGContextSaveGState(ctx);
  69. // 阴影
  70. UIColor *shadowColor = [UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:0.2000];
  71. CGContextSaveGState(ctx);
  72. CGContextSetShadowWithColor(ctx, CGSizeMake(0,4.4), 11.1, shadowColor.CGColor);
  73. // 大圆点
  74. CGPoint handleCenter = [self pointFromAngle: _angle];
  75. [_handleColor set];
  76. CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x-8, handleCenter.y-8, _lineWidth+16, _lineWidth+16));
  77. CGContextRestoreGState(ctx);
  78. // 中间小圆点
  79. CGFloat width = 18;
  80. CGContextSaveGState(ctx);
  81. [_handleColor2 set];
  82. CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x-(width-_lineWidth)/2, handleCenter.y-(width-_lineWidth)/2, width, width));
  83. CGContextRestoreGState(ctx);
  84. // 和线一样宽度的圆点,默认透明隐藏,设置了_handleColor3颜色才显示
  85. CGContextSaveGState(ctx);
  86. [_handleColor3 set];
  87. CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x, handleCenter.y, _lineWidth, _lineWidth));
  88. CGContextRestoreGState(ctx);
  89. }
  90. -(CGPoint)pointFromAngle:(int)angleInt{
  91. //Define the Circle center
  92. CGPoint centerPoint = CGPointMake(self.frame.size.width/2 - _lineWidth/2, self.frame.size.height/2 - _lineWidth/2);
  93. //Define The point position on the circumference
  94. CGPoint result;
  95. result.y = round(centerPoint.y + radius * sin(ToRad(angleInt))) ;
  96. result.x = round(centerPoint.x + radius * cos(ToRad(angleInt)));
  97. return result;
  98. }
  99. -(BOOL) beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
  100. [super beginTrackingWithTouch:touch withEvent:event];
  101. return YES;
  102. }
  103. -(BOOL) continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
  104. [super continueTrackingWithTouch:touch withEvent:event];
  105. CGPoint lastPoint = [touch locationInView:self];
  106. //用于排除点在圆外面点与圆心半径80以内的点
  107. // if ((lastPoint.x>=0&&lastPoint.x<=275)&&(lastPoint.y>=0 && lastPoint.y<=275)) {
  108. // if ((lastPoint.x<=57.5 ||lastPoint.x>=217.5)||(lastPoint.y<=57.5 ||lastPoint.y>=217.5)) {
  109. [self moveHandle:lastPoint];
  110. // }
  111. // }
  112. [self sendActionsForControlEvents:UIControlEventValueChanged];
  113. return YES;
  114. }
  115. -(void)moveHandle:(CGPoint)point {
  116. CGPoint centerPoint = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
  117. int currentAngle = floor(AngleFromNorth(centerPoint, point, NO));
  118. if (currentAngle>40 && currentAngle <140) {
  119. }else{
  120. if (currentAngle<=40) {
  121. _angle = currentAngle+360;
  122. }else{
  123. _angle = currentAngle;
  124. }
  125. }
  126. _currentValue =[self valueFromAngle];
  127. [self setNeedsDisplay];
  128. }
  129. static inline float AngleFromNorth(CGPoint p1, CGPoint p2, BOOL flipped) {
  130. CGPoint v = CGPointMake(p2.x-p1.x,p2.y-p1.y);
  131. float vmag = sqrt(SQR(v.x) + SQR(v.y)), result = 0;
  132. v.x /= vmag;
  133. v.y /= vmag;
  134. double radians = atan2(v.y,v.x);
  135. result = ToDeg(radians);
  136. return (result >=0 ? result : result + 360.0);
  137. }
  138. //在这个地方调整进度条
  139. -(float) valueFromAngle {
  140. CGFloat curValue = _currentValue;
  141. if(_angle <= 40) {
  142. curValue = 220+_angle;
  143. } else if(_angle>40 && _angle < 140){
  144. }else{
  145. curValue = _angle-100-40;
  146. }
  147. _fixedAngle = curValue;
  148. CGFloat value = (curValue*(_maximumValue - _minimumValue))/260.0f;
  149. // 四舍五入 档位
  150. int a;
  151. a = (int)(value + 0.5);
  152. _angle = (int)260/(_maximumValue - _minimumValue)*a+140;
  153. if(a != _currentValue){
  154. _currentValue = a;// 档位
  155. _value = (int)(a+_minimumValue);// 用户设置的值
  156. //DDLog(@"Value:%d",_value);
  157. [self.delegate senderVlueChangingWithNum:_value];
  158. }
  159. return a;
  160. }
  161. -(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
  162. [super endTrackingWithTouch:touch withEvent:event];
  163. [self.delegate senderVlueWithNum:_value];
  164. }
  165. #pragma mark 设置进度条位置
  166. - (void)setValue:(int)value{
  167. _value = value;
  168. if(value > _maximumValue){
  169. _currentValue = _maximumValue - _minimumValue;
  170. }else if (value < _minimumValue){
  171. _currentValue = 0;
  172. }else{
  173. _currentValue = value - _minimumValue;
  174. }
  175. _angle = (int)260/(_maximumValue - _minimumValue)*_currentValue+140;
  176. [self setNeedsDisplay];
  177. }
  178. -(void)setAddAngel{
  179. _angle += (int)260/(_maximumValue - _minimumValue);
  180. if (_angle>400) {
  181. _angle = 400;
  182. }
  183. [self setNeedsDisplay];
  184. _currentValue =[self valueFromAngle];
  185. }
  186. -(void)setMovAngel{
  187. _angle -= (int)260/(_maximumValue - _minimumValue);
  188. if (_angle<140) {
  189. _angle = 140;
  190. }
  191. [self setNeedsDisplay];
  192. _currentValue =[self valueFromAngle];
  193. }
  194. @end