主要用到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