iOS 弧形渐变色进度条
2019-10-11 本文已影响0人
贤宇
2019-09-06 14-53-31.2019-09-06 14_55_17.gif最近产品需求要搞个弧形进度条, 研究了一下仅供参考.
核心代码
// ----- CTArcProgressView .h
@interface CTArcProgressView : UIView
@property (nonatomic, assign) CGFloat oneProgress;
@property (nonatomic, assign) CGFloat twoProgress;
@end
// ----- CTArcProgressView .m
@interface CTArcProgressView ()
// 背景
@property (nonatomic, strong) CAShapeLayer *bgShapeLayer;
// 渐变色
@property (nonatomic, strong) CAGradientLayer *gradientLayer;
// 进度
@property (nonatomic, strong) CAShapeLayer *progressOneLayer;
@property (nonatomic, strong) CAShapeLayer *progressTwoLayer;
// 进度圆点
@property (nonatomic, strong) CTArcProgressDotView *oneDotView;
@property (nonatomic, strong) CTArcProgressDotView *twoDotView;
// 进度描述
@property (nonatomic, strong) UILabel *oneNameLabel;
@property (nonatomic, strong) UILabel *twoNameLabel;
// 距离
@property (nonatomic, assign) CGFloat arcW;
@property (nonatomic, assign) CGFloat arcR;
@property (nonatomic, assign) CGFloat arcX;
@property (nonatomic, assign) CGFloat arcY;
@property (nonatomic, assign) CGFloat dotW;
@end
@implementation CTArcProgressView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self customView];
}
return self;
}
- (void)customView {
self.arcW = 8.0;
CGFloat r = KScreenWidth() > 375 ? 232 : 228;
self.arcR = KAuToLayoutSize(r/2.0);
self.arcX = (self.width - self.arcR*2 - self.arcW)/2;
self.arcY = (self.height - self.arcR - self.arcW);
self.dotW = 21.0;
// 背景加阴影
CAShapeLayer *shadowShaperLayer = [self creatShapeLayerWithStrokeEnd:1 strokeColor:Style.blackColor_96B6DA showShadow:YES startAngle:M_PI endAngle:M_PI*2 clockwise:YES];
[self.layer addSublayer:shadowShaperLayer];
// 背景色
_bgShapeLayer = [self creatShapeLayerWithStrokeEnd:1 strokeColor:Style.blackColor_96B6DA showShadow:NO startAngle:M_PI endAngle:M_PI*2 clockwise:YES];
// 进度1
_progressOneLayer = [self creatShapeLayerWithStrokeEnd:0 strokeColor:[UIColor redColor] showShadow:NO startAngle:M_PI*1.5 endAngle:M_PI clockwise:NO];
// 进度2
_progressTwoLayer = [self creatShapeLayerWithStrokeEnd:0 strokeColor:[UIColor greenColor] showShadow:NO startAngle:M_PI*1.5 endAngle:M_PI*2 clockwise:YES];
[self.layer addSublayer:_bgShapeLayer];
[self.layer addSublayer:_progressOneLayer];
[self.layer addSublayer:_progressTwoLayer];
// 渐变图层映射到进度条路径上面 关键步骤
_gradientLayer = [self creatGradientLayer];
[_gradientLayer setMask:_bgShapeLayer];
[self.layer addSublayer:_gradientLayer];
[self addSubview:self.oneDotView];
[self addSubview:self.twoDotView];
[self addSubview:self.oneNameLabel];
[self.oneNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.oneDotView.mas_left);
make.bottom.equalTo(self.oneDotView.mas_top);
}];
[self addSubview:self.twoNameLabel];
[self.twoNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.twoDotView.mas_right);
make.bottom.equalTo(self.twoDotView.mas_top);
}];
self.oneProgress = 0.0;
self.twoProgress = 0.0;
}
// 轨迹
- (CAShapeLayer *)creatShapeLayerWithStrokeEnd:(CGFloat)strokeEnd
strokeColor:(UIColor *)strokeColor
showShadow:(BOOL)showShadow
startAngle:(CGFloat)startAngle
endAngle:(CGFloat)endAngle
clockwise:(BOOL)clockwise {
UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.width/2, self.height-self.arcW/2) radius:self.arcR startAngle:startAngle endAngle:endAngle clockwise:clockwise];
CAShapeLayer *bgShapeLayer = [CAShapeLayer layer];
bgShapeLayer.frame = self.bounds;
bgShapeLayer.fillColor = [UIColor clearColor].CGColor;
bgShapeLayer.lineWidth = self.arcW;
bgShapeLayer.lineCap = kCALineCapRound;
bgShapeLayer.lineJoin = kCALineJoinRound;
bgShapeLayer.strokeColor = Style.blackColor_96B6DA.CGColor;
bgShapeLayer.strokeStart = 0;
bgShapeLayer.strokeEnd = strokeEnd;
bgShapeLayer.path = circlePath.CGPath;
if (showShadow) {
bgShapeLayer.shadowColor = Style.orangeColor_A9591D.CGColor;
bgShapeLayer.shadowOffset = CGSizeMake(0, 2);
bgShapeLayer.shadowRadius = 5;
bgShapeLayer.shadowOpacity = 0.3;
}
return bgShapeLayer;
}
// 渐变色
- (CAGradientLayer *)creatGradientLayer {
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = self.bounds;
//左边渐变图层
CAGradientLayer *leftGradientLayer = [CAGradientLayer layer];
leftGradientLayer.frame = CGRectMake(self.arcX, self.arcY, self.arcR+self.arcW/2, self.arcR+self.arcW);
[leftGradientLayer setColors:@[(id)Style.orangeColor_F3C174.CGColor, (id)Style.greenColor_5DC8A1.CGColor]];
// 开始渐变色位置 0-1 为整个layer
[leftGradientLayer setLocations:@[@0.2,@0.7]];
// 渐变色方向
[leftGradientLayer setStartPoint:CGPointMake(0, 1)];
[leftGradientLayer setEndPoint:CGPointMake(1, 0)];
[gradientLayer addSublayer:leftGradientLayer];
// 右边渐变图层
CAGradientLayer *rightGradientLayer = [CAGradientLayer layer];
rightGradientLayer.frame = CGRectMake(self.arcX+self.arcR+self.arcW/2, self.arcY, self.arcR+self.arcW/2, self.arcR+self.arcW);
[rightGradientLayer setColors:@[(id)Style.greenColor_5DC8A1.CGColor, (id)Style.orangeColor_F3C174.CGColor]];
[rightGradientLayer setLocations:@[@0.3, @0.8]];
[rightGradientLayer setStartPoint:CGPointMake(0, 0)];
[rightGradientLayer setEndPoint:CGPointMake(1, 1)];
[gradientLayer addSublayer:rightGradientLayer];
return gradientLayer;
}
- (void)setOneProgress:(CGFloat)oneProgress {
_oneProgress = oneProgress;
// 是否安全区域
if (_oneProgress < 0.3) {
self.oneDotView.isSafe = YES;
} else {
self.oneDotView.isSafe = NO;
}
[self confineOneProgress];
[self updateOneProgress];
}
- (void)setTwoProgress:(CGFloat)twoProgress {
_twoProgress = twoProgress;
if (twoProgress < 0.3) {
self.twoDotView.isSafe = YES;
} else {
self.twoDotView.isSafe = NO;
}
[self confineTwoProgress];
[self updateTwoProgress];
}
// 限制进度
- (void)confineOneProgress {
if (_oneProgress < 0.05) _oneProgress = 0.05; // 防止重合
if (_oneProgress > 1) _oneProgress = 1;
}
- (void)confineTwoProgress {
if (_twoProgress < 0.05) _twoProgress = 0.05;
if (_twoProgress > 1) _twoProgress = 1;
}
// 更新进度
- (void)updateOneProgress {
_progressOneLayer.strokeEnd = _oneProgress;
CGFloat angle = 90.0 + 90.0 * _oneProgress;
CGPoint point = [self calcCircleCoordinateWithCenter:CGPointMake(self.width/2, self.height-self.arcW/2) andWithAngle:angle andWithRadius:self.arcR];
self.oneDotView.center = point;
}
- (void)updateTwoProgress {
_progressTwoLayer.strokeEnd = _twoProgress;
CGFloat angle = 90.0 * (1 - _twoProgress);
CGPoint point = [self calcCircleCoordinateWithCenter:CGPointMake(self.width/2, self.height-self.arcW/2) andWithAngle:angle andWithRadius:self.arcR];
self.twoDotView.center = point;
}
- (CTArcProgressDotView *)oneDotView {
if (!_oneDotView) {
_oneDotView = [[CTArcProgressDotView alloc] initWithFrame:CGRectMake(self.arcX-self.dotW/4, self.height-self.dotW, self.dotW, self.dotW)];
_oneDotView.isSafe = YES;
}
return _oneDotView;
}
- (CTArcProgressDotView *)twoDotView {
if (!_twoDotView) {
_twoDotView = [[CTArcProgressDotView alloc] initWithFrame:CGRectMake(self.arcX-self.dotW/4, self.height-self.dotW, self.dotW, self.dotW)];
_oneDotView.isSafe = YES;
}
return _twoDotView;
}
- (UILabel *)oneNameLabel {
if (!_oneNameLabel) {
_oneNameLabel = [self creatNameLabelWithText:@"增值税"];
}
return _oneNameLabel;
}
- (UILabel *)twoNameLabel {
if (!_twoNameLabel) {
_twoNameLabel = [self creatNameLabelWithText:@"企业所得税"];
}
return _twoNameLabel;
}
- (UILabel *)creatNameLabelWithText:(NSString *)text {
UILabel *nameLabel = [[UILabel alloc] init];
nameLabel = [[UILabel alloc] init];
nameLabel.textColor = Style.blackColor_414141;
nameLabel.font = [UIFont systemFontOfSize:12];
nameLabel.textAlignment = NSTextAlignmentCenter;
nameLabel.text = text;
[nameLabel sizeToFit];
return nameLabel;
}
/**
@param center 中心点
@param angle 角度 0-360
@param radius 半径
@return 圆上坐标
*/
- (CGPoint)calcCircleCoordinateWithCenter:(CGPoint)center andWithAngle:(CGFloat)angle andWithRadius:(CGFloat)radius{
CGFloat x2 = radius*cosf(angle*M_PI/180);
CGFloat y2 = radius*sinf(angle*M_PI/180);
return CGPointMake(center.x+x2, center.y-y2);
}
/*
--------------------------------------------------------------
功能说明
--------------------------------------------------------------
根据IOS视图中圆组件的中心点(x,y)、半径(r)、圆周上某一点与圆心的角度这3个
条件来计算出该圆周某一点在IOS中的坐标(x2,y2)。
注意:
(1)IOS坐标体系与数学坐标体系有差别,因此不能完全采用数学计算公式。
(2)数学计算公式:
x2=x+r*cos(角度值*PI/180)
y2=y+r*sin(角度值*PI/180)
(3)IOS中计算公式:
x2=x+r*cos(角度值*PI/180)
y2=y-r*sin(角度值*PI/180)
--------------------------------------------------------------
参数说明
--------------------------------------------------------------
@param (CGPoint) center
圆圈在IOS视图中的中心坐标,即该圆视图的center属性
@param (CGFloat) angle
角度值,是0~360之间的值。
注意:
(1)请使用下面坐标图形进行理解。
(2)角度是逆时针转的,从x轴中心(0,0)往右是0度角(或360度角),往左是180度角,往上是90度角,往下是270度角。
(y)90
^
|
|
|
|
180 -----------------> (x)0/360
|(0,0)
|
|
|
270
@param (CGFloat) radius
圆周半径
*/
@end
圆点
// 进度圆点
@interface CTArcProgressDotView : UIView
@property (nonatomic,strong) UIView *centerView;
@property (nonatomic,assign) BOOL isSafe; // 是否安全 YES绿色 NO黄色
@end
@implementation CTArcProgressDotView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self customView];
}
return self;
}
- (void)setIsSafe:(BOOL)isSafe {
_isSafe = isSafe;
UIColor *safeCenterColor = Style.greenColor_5DC8A1;
UIColor *safeBgColor = [Style.greenColor_DEF1D6 colorWithAlphaComponent:0.8];
UIColor *noSafeCenterColor = Style.orangeColor_F2BC68;
UIColor *noSafeBgColor = [Style.orangeColor_FFECCE colorWithAlphaComponent:0.8];
if (isSafe) {
self.centerView.backgroundColor = safeCenterColor;
self.backgroundColor = safeBgColor;
self.layer.shadowColor = safeCenterColor.CGColor;
} else {
self.centerView.backgroundColor = noSafeCenterColor;
self.backgroundColor = noSafeBgColor;
self.layer.shadowColor = noSafeCenterColor.CGColor;
}
}
- (void)customView {
self.layer.cornerRadius = self.width/2.0;
self.layer.shadowColor = Style.blackColor_96B6DA.CGColor;
self.layer.shadowOffset = CGSizeMake(0, 2);
self.layer.shadowRadius = 5;
self.layer.shadowOpacity = 0.5;
self.centerView.backgroundColor = [UIColor redColor];
self.centerView.layer.cornerRadius = (self.width-8)/2.0;
[self addSubview:self.centerView];
[self.centerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self);
make.width.equalTo(@(self.width-8));
make.height.equalTo(@(self.height-8));
}];
}
- (UIView *)centerView {
if (!_centerView) {
_centerView = [[UIView alloc] init];
}
return _centerView;
}
@end