天天看點

漸變、虛線、圓形進度條

主要用到CAShapeLayer,CAGradientLayer 結合實作圓形進度條

  • 可設定是否是虛線
  • 可設定起始角度
  • 可設定進度條方向
  • 可設定進度條線寬
  • 可設定虛線的長度
  • 可設定背景圓環顔色
  • 可設定背景進度條的閉合樣式
  • 可設定是否顯示背景圓環
/// 漸變色 layer
@property (nonatomic, strong) CAGradientLayer *progressGradientLayer;
/// 底色 layer
@property (nonatomic, strong) CAShapeLayer *bottomLayer;
/// 進度遮罩layer   加在漸變 層上的mask
@property (nonatomic, strong) CAShapeLayer *progressLayer;
           

通過設定progressLayer的Path改變進度

主要代碼

- RoundProgressView.h

/**
 * 圓形進度條
 * - 可設定是否是虛線
 * - 可設定起始角度
 * - 可設定進度條方向
 * - 可設定進度條線寬
 * - 可設定虛線的長度
 * - 可設定背景圓環顔色
 * - 可設定背景進度條的閉合樣式
 * - 可設定是否顯示背景圓環
 */
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface RoundProgressView : UIView

/// 起始角度
@property (nonatomic, assign) CGFloat  startAngle;
/// 是否是順時針
@property (nonatomic, assign) BOOL  isClockwise;
/// 0-1.0
@property (nonatomic, assign) CGFloat  progress;
/// 線寬
@property (nonatomic, assign) CGFloat  lineWidth;
/// 是否以虛線形式展示注意線段間隔太短時會受到lineCap影響可能看不到效果
@property (nonatomic, assign) BOOL  shouldWithDashPattern;
///虛線長度設定
@property (nonatomic, strong) NSArray *dashPattern;
///背景圓環顔色
@property (nonatomic, strong) UIColor *maxTintColor;
///進度條的漸變色
@property (nonatomic, copy) NSArray *progressColors;
///進度條閉合方式
@property (nonatomic, copy) CAShapeLayerLineCap lineCap;
///是否顯示底部圓環
@property (nonatomic, assign) BOOL  showBottomProgress;

/// 設定進度條漸變色的相關屬性
/// @param handle 回調
- (void)setProgressGradientLayerHandle:(void(^)(CAGradientLayer *gradientLayer))handle;

/// 設定進度條線寬虛線進度等相關屬性
/// @param handle 回調
- (void)setProgressLayerHandle:(void(^)(CAShapeLayer *progressLayer))handle;

/// 設定底部圓環相關屬性
/// @param handle 回調
- (void)setBottomLayerHandle:(void(^)(CAShapeLayer *bottomLayer))handle;
@end

NS_ASSUME_NONNULL_END
           

- RoundProgressView.m

#import "RoundProgressView.h"
#define kSelfWidth self.frame.size.width
#define kSelfHeight self.frame.size.height
@interface RoundProgressView()
@property (nonatomic, strong) UILabel *inforLabel;
/// 漸變色 layer
@property (nonatomic, strong) CAGradientLayer *progressGradientLayer;
/// 底色 layer
@property (nonatomic, strong) CAShapeLayer *bottomLayer;
/// 進度遮罩layer   加在漸變 層上的mask
@property (nonatomic, strong) CAShapeLayer *progressLayer;
@end

@implementation RoundProgressView

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        _startAngle = 0;
        _isClockwise = YES;
        _lineWidth = 4;
        _shouldWithDashPattern = NO;
        _dashPattern = @[@(2),@(2)];
        _lineCap = kCALineCapRound;
        _maxTintColor = [UIColor grayColor];
        _startAngle = 0;
        _showBottomProgress = YES;
        _progressColors = @[(id)UIColor.orangeColor.CGColor,(id)UIColor.redColor.CGColor];
        [self.layer addSublayer:self.bottomLayer];
        [self.layer addSublayer:self.progressGradientLayer];
        [self addSubview:self.inforLabel];
        
    }
    return self;
}
- (void)layoutSubviews {
    [super layoutSubviews];
    self.bottomLayer.frame = self.bounds;
    self.progressLayer.frame = self.bounds;
    self.progressGradientLayer.frame = self.bounds;
    [self p_drawBottom];
    _inforLabel.frame = self.bounds;
}

/// 重繪
- (void)redrawProgress {
    [self p_drawBottom];
    [self p_drawProgress];
}

/// 繪制進度mask
- (void)p_drawProgress {
    CGPoint center = CGPointMake(kSelfWidth/2.0, kSelfHeight/2.0);
    CGFloat radius = kSelfWidth/2.0-_lineWidth/2.0;
    CGFloat endAngle = M_PI * 2 *_progress + _startAngle;
    if (!_isClockwise) {
        endAngle = _startAngle - M_PI * 2 *_progress;
    }
    self.progressLayer.path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:_startAngle endAngle:endAngle clockwise:_isClockwise].CGPath;
}

/// 繪制底色layer
- (void)p_drawBottom {
    CGPoint center = CGPointMake(kSelfWidth/2.0, kSelfHeight/2.0);
    CGFloat radius = kSelfWidth/2.0-_lineWidth/2.0;
    CGFloat endAngle = M_PI * 2 + _startAngle;
    if (!_isClockwise) {
        endAngle = _startAngle - M_PI * 2;
    }
    self.bottomLayer.path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:_startAngle endAngle:endAngle clockwise:_isClockwise].CGPath;
}


#pragma mark - Public Methods
- (void)setProgressGradientLayerHandle:(void (^)(CAGradientLayer * _Nonnull))handle {
    if (handle) {
        handle(self.progressGradientLayer);
    }
}
- (void)setProgressLayerHandle:(void (^)(CAShapeLayer * _Nonnull))handle {
    if (handle) {
        handle(self.progressLayer);
        [self p_drawProgress];
    }
}
- (void)setBottomLayerHandle:(void (^)(CAShapeLayer * _Nonnull))handle {
    if (handle) {
        handle(self.bottomLayer);
        [self p_drawBottom];
    }
}
#pragma mark - setterMethods
- (void)setProgressColors:(NSArray *)progressColors {
    _progressColors = progressColors.copy;
    self.progressGradientLayer.colors = progressColors;
}
- (void)setLineWidth:(CGFloat)lineWidth {
    _lineWidth = lineWidth;
    self.bottomLayer.lineWidth = _lineWidth;
    self.progressLayer.lineWidth = _lineWidth;
    [self redrawProgress];
}
- (void)setProgress:(CGFloat)progress {
    _progress = progress;
    self.inforLabel.text = [NSString stringWithFormat:@"%ld%%",(NSInteger)(_progress*100)%101];
    [self p_drawProgress];
}
- (void)setShouldWithDashPattern:(BOOL)shouldWithDashPattern {
    _shouldWithDashPattern = shouldWithDashPattern;
    if (_shouldWithDashPattern && _dashPattern.count) {
        self.progressLayer.lineDashPattern = _dashPattern;
        self.bottomLayer.lineDashPattern = _dashPattern;
    } else {
        self.progressLayer.lineDashPattern = nil;
        self.bottomLayer.lineDashPattern = nil;
    }
    [self redrawProgress];
}
- (void)setDashPattern:(NSArray *)dashPattern {
    _dashPattern = [dashPattern copy];
    if (_shouldWithDashPattern && _dashPattern.count) {
        self.progressLayer.lineDashPattern = _dashPattern;
        self.bottomLayer.lineDashPattern = _dashPattern;
    } else {
        self.progressLayer.lineDashPattern = nil;
        self.bottomLayer.lineDashPattern = nil;
    }
    [self redrawProgress];
}
- (void)setLineCap:(CAShapeLayerLineCap)lineCap {
    _lineCap = [lineCap copy];
    self.progressLayer.lineCap = _lineCap;
    self.bottomLayer.lineCap = _lineCap;
    [self redrawProgress];
}
- (void)setMaxTintColor:(UIColor *)maxTintColor {
    _maxTintColor = maxTintColor;
    self.bottomLayer.strokeColor = _maxTintColor.CGColor;
    [self p_drawBottom];
}
- (void)setStartAngle:(CGFloat)startAngle {
    _startAngle = startAngle;
    [self redrawProgress];
}
- (void)setIsClockwise:(BOOL)isClockwise {
    _isClockwise = isClockwise;
    [self redrawProgress];
}
- (void)setShowBottomProgress:(BOOL)showBottomProgress {
    _showBottomProgress = showBottomProgress;
    self.bottomLayer.hidden = !_showBottomProgress;
}
#pragma mark - getterMethods
- (CAShapeLayer *)bottomLayer {
    if (!_bottomLayer) {
        _bottomLayer = [CAShapeLayer layer];
        _bottomLayer.lineWidth = _lineWidth;
        _bottomLayer.lineCap = _lineCap;
        _bottomLayer.strokeStart = 0;
        _bottomLayer.strokeEnd = 1;
        _bottomLayer.fillColor = [UIColor clearColor].CGColor;
        _bottomLayer.strokeColor = _maxTintColor.CGColor;
        _bottomLayer.hidden = !_showBottomProgress;
    }
    return _bottomLayer;
}
- (CAGradientLayer *)progressGradientLayer {
    if (!_progressGradientLayer) {
        _progressGradientLayer = [CAGradientLayer layer];
        _progressGradientLayer.startPoint = CGPointZero;
        _progressGradientLayer.endPoint = CGPointMake(1, 1);
        _progressGradientLayer.locations = @[@(0),@(1)];
        _progressGradientLayer.colors = _progressColors;
        self.progressGradientLayer.mask=  self.progressLayer;
    }
    return _progressGradientLayer;
}
- (CAShapeLayer *)progressLayer {
    if (!_progressLayer) {
        _progressLayer = [CAShapeLayer layer];
        _progressLayer.lineWidth = _lineWidth;
        _progressLayer.lineCap = _lineCap;
        _progressLayer.strokeStart = 0;
        _progressLayer.strokeEnd = 1;
        _progressLayer.strokeColor = UIColor.greenColor.CGColor;
        _progressLayer.fillColor = UIColor.clearColor.CGColor;
    }
    return _progressLayer;
}
- (UILabel *)inforLabel {
    if (!_inforLabel) {
        _inforLabel = [[UILabel alloc] init];
        _inforLabel.textColor = [UIColor redColor];
        _inforLabel.font = [UIFont systemFontOfSize:20];
        _inforLabel.numberOfLines = 0;
        _inforLabel.text = [NSString stringWithFormat:@"%ld%%",(NSInteger)(_progress*100)%101];
        _inforLabel.textAlignment = NSTextAlignmentCenter;
    }
    return _inforLabel;
}
@end
           

效果展示

漸變、虛線、圓形進度條
漸變、虛線、圓形進度條
漸變、虛線、圓形進度條

源碼:

CircleProgressDemo