iOS 手动画弧形进度条
2020-08-28 本文已影响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