扇形进度条 - iOS

绘制扇形进度条

背景:上传文件的时候,需要有上传进度,这次需要一个扇形的进度条,示例图如下:


背景.jpg

废话不多说,上代码:

/**
 扇形图进度条
 角度:可选择起始角度:SLSectorStartAngle:top left bottom and right
 旋转:顺时针旋转
 半径:radius
 填充色:fillColor
 */

#import 

NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, SLSectorStartAngle) {
    SLSectorStartAngle_top = 0,
    SLSectorStartAngle_left,
    SLSectorStartAngle_bottom,
    SLSectorStartAngle_right,
};

@interface SLSectorProgressBar : UIView

/// 构造方法
/// @param startAngle 初始角度
- (instancetype)initWithStartAngle:(SLSectorStartAngle)startAngle radius:(CGFloat)radius fillColor:(UIColor *)fillColor;

/// 进度
@property(nonatomic, assign) CGFloat progress;

/// 配置边框颜色和宽度
/// @param borderColor 边框颜色
/// @param borderWidth 边框宽度
- (void)configBorderWithColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth;

/// 没有进度时,是否需要占位线(如果需要下面的绘制外圈的圆圈,一般都需要绘制默认占位线)
@property (nonatomic, assign) BOOL needPlaceholderLine;
@end

#import "SLSectorProgressBar.h"

@interface SLSectorProgressBar ()

/// 开始角度
@property (nonatomic, assign) SLSectorStartAngle startAngle;
/// 半径
@property (nonatomic, assign) CGFloat radius;
/// 填充色
@property (nonatomic, strong) UIColor *fillColor;
/// 边框颜色
@property (nonatomic, strong) UIColor *borderColor;
/// 边框粗细
@property (nonatomic, assign) CGFloat borderWidth;
@end

@implementation SLSectorProgressBar

- (instancetype)initWithStartAngle:(SLSectorStartAngle)startAngle radius:(CGFloat)radius fillColor:(UIColor *)fillColor {
    if (self = [super init]) {
        self.backgroundColor = [UIColor clearColor];
        
        _startAngle = startAngle;
        _radius = radius ?: 200;
        _fillColor = fillColor ?: [UIColor cyanColor];
    }
    return self;
}

- (void)configBorderWithColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth {
    _borderColor = borderColor;
    _borderWidth = borderWidth;
}

#pragma mark - 更新进度

- (void)setProgress:(CGFloat)progress{
    _progress = progress;
    
    [self setNeedsDisplay];
}


#pragma mark - 绘制图形

- (void)drawRect:(CGRect)rect {
    [self drawLine];
    [self drawProgress];
}

// 绘制外圈线条
- (void)drawLine {
    CGPoint origin = CGPointMake(_radius/2, _radius/2);
    CGFloat radius = _radius/2 - _borderWidth/2;
    CGFloat startAngle = 0;
    CGFloat endAngle = 2*M_PI;
    UIBezierPath *sectorPath = [UIBezierPath bezierPathWithArcCenter:origin radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
  if (self.needPlaceholderLine) {
        [sectorPath moveToPoint:origin];
        [sectorPath addLineToPoint:CGPointMake(_radius/2, 0)];
    }
    sectorPath.lineWidth = _borderWidth;
    [_borderColor set];
    [sectorPath strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}

// 绘制进度条
- (void)drawProgress {
    // 中心点
    CGPoint origin = CGPointMake(_radius/2, _radius/2);
    // 半径
    CGFloat radius = _radius/2;
    // 起始角度
    CGFloat startAngle = [self fetchStartAngle];
    // 结束角度
    CGFloat endAngle = [self fetchEndAngle];
    // 开始绘制
    UIBezierPath *sectorPath = [UIBezierPath bezierPathWithArcCenter:origin radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
    [sectorPath addLineToPoint:origin];
    [_fillColor set];
    [sectorPath fill];
}


#pragma mark - Tools

- (CGFloat)fetchStartAngle {
    CGFloat angle = - M_PI_2; // 默认top
    switch (_startAngle) {
        case SLSectorStartAngle_left:
            angle = M_PI;
            break;
        case SLSectorStartAngle_bottom:
            angle = M_PI_2;
            break;
        case SLSectorStartAngle_right:
            angle = M_PI * 2;
            break;
        default:
            break;
    }
    return angle;
}

- (CGFloat)fetchEndAngle {
    CGFloat angle = [self fetchStartAngle] + self.progress * M_PI * 2;
    return angle;
}

@end

以上代码的调用方式如下:


#import "ViewController.h"
#import "SLSectorProgressBar.h"

@interface ViewController ()

@property (nonatomic, strong) UISlider *slider;
@property (nonatomic, strong) SLSectorProgressBar *sectorView;
@property (nonatomic, strong) UIColor *testColor;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.testColor = [UIColor redColor];
    
    [self.view addSubview:self.slider];
    [self.view addSubview:self.sectorView];
}

- (void)sliderValueChange:(UISlider *)sender {
    self.sectorView.progress = (sender.value - sender.minimumValue) / (sender.maximumValue - sender.minimumValue);
}

- (UISlider *)slider {
    if (_slider == nil) {
        _slider = [[UISlider alloc] initWithFrame:CGRectMake(50, 100, self.view.frame.size.width - 100, 50)];
        [_slider addTarget:self action:@selector(sliderValueChange:) forControlEvents:UIControlEventValueChanged];
        [_slider setMinimumTrackTintColor:self.testColor];
    }
    return _slider;
}

- (SLSectorProgressBar *)sectorView {
    if (_sectorView == nil) {
        _sectorView = [[SLSectorProgressBar alloc] initWithStartAngle:SLSectorStartAngle_top radius:200 fillColor: self.testColor];
        [_sectorView configBorderWithColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.1] borderWidth:3];
        _sectorView.progress = 0;

        CGFloat wh = 200;
        CGFloat y = CGRectGetMaxY(self.slider.frame) + 10;
        CGFloat x = (self.view.frame.size.width - wh) / 2;
        _sectorView.frame = CGRectMake(x, y, wh, wh);
    }
    return _sectorView;
}
@end

按照上面代码跑起来,示例图如下:


demo.jpg

你可能感兴趣的:(扇形进度条 - iOS)