logo头像

学如逆水行舟

带动画渐进效果与颜色渐变的圆弧进度控件设计

带动画渐进效果与颜色渐变的圆弧进度控件设计

今天帮朋友写了一个小巧的圆弧进度控件,控件十分简单,主要设计思路采用CAShapeLayer来创建控件圆弧形状,使用CAGradientLayer来进行颜色渐变的渲染,两者结合来创建出颜色渐变的圆弧进度条控件,关于进度动画采用CoreAnimation动画处理。控件进行了简洁的封装,提供了面向使用的接口,需要的朋友可以自取,Demo地址如下:

http://pan.baidu.com/s/1gfqDbtp

控件中主要提供了,改变进度条渐变颜色,圆弧进度条宽度,带动画效果的改变进度,改变进度百分比字体颜色等方法。效果是例如如下:

改变字体颜色

改变进度

改变进度条颜色

改变进度条宽度

控件接口的设计:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#import <UIKit/UIKit.h>
@interface YHBaseCircleView : UIView
//==============下面三个渐变色必须全部设置 否则效果可能与预期不同================//
/**
 *设置圆弧渐变色的起始色
 */
@property(nonatomic,strong)UIColor * minLineColor;
/**
 *设置圆弧渐变色的中间色
 */
@property(nonatomic,strong)UIColor * midLineColor;
/**
 *设置圆弧渐变色的终止色
 */
@property(nonatomic,strong)UIColor * maxLineColor;
/**
 *设置圆弧背景色
 */
@property(nonatomic,strong)UIColor * lineTintColor;
/**
 *设置进度
 */
@property(nonatomic,assign)CGFloat progress;
/**
 *设置线的宽度 max = 20 min = 0.5
 */
@property(nonatomic,assign)CGFloat lineWidth;
/**
 *设置是否显示百分比标签
 */
@property(nonatomic,assign)BOOL showTipLabel;
/**
 *设置百分比标签进度颜色
 */
@property(nonatomic,strong)UIColor * textColor;
/**
 *  @brief 设置进度
 *
 *  @param progress 进度 取值0-1
 *
 *  @param animated 是否显示动画
 *
 */
-(void)setProgress:(CGFloat)progress animated:(BOOL)animated;
@end

实现方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#import "YHBaseCircleView.h"
@implementation YHBaseCircleView
{
    //进度控件内容尺寸
    float _contentWidth;
    float _contentHeight;
    //形状layer
    CAShapeLayer * _shapeLayer;
    //颜色渐变layer
    CAGradientLayer * _gradLayerR;
    CAGradientLayer * _gradLayerL;
    CALayer * _gradLayer;
    //内容layer
    CAShapeLayer * _contentLayer;
    UILabel * _tipLabel;
    //专门用来更新label
    NSTimer * _timer;
    float _oldProgress;
    //进度新旧进度值
    int old;
    int new;
}

-(void)awakeFromNib{
    [self reloadView];
}
-(instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        [self reloadView];
    }
    return self;
}

-(void)reloadView{
    self.backgroundColor = [UIColor clearColor];
    //取设置的frame的最小长或款作为内容区域
    _contentWidth = _contentHeight = CGRectGetWidth(self.frame)>CGRectGetHeight(self.frame)?CGRectGetHeight(self.frame):CGRectGetWidth(self.frame);
    //创建内容layer
    _contentLayer = [CAShapeLayer layer];
    _contentLayer.bounds = CGRectMake(0, 0, _contentWidth, _contentHeight);
    _contentLayer.position = CGPointMake(_contentWidth/2, _contentHeight/2);
    _contentLayer.backgroundColor = [UIColor clearColor].CGColor;
    //进行边界描绘 默认线宽为4px
    UIBezierPath * pathT = [UIBezierPath bezierPathWithArcCenter:_contentLayer.position radius:_contentWidth/2-2 startAngle:-M_PI_2 endAngle:M_PI_2*3 clockwise:YES];
    _contentLayer.path = pathT.CGPath;
    //默认填充颜色为白色
    _contentLayer.fillColor = [UIColor whiteColor].CGColor;
    _contentLayer.lineWidth = 4;
    _contentLayer.strokeColor = [UIColor grayColor].CGColor;
    [self.layer addSublayer:_contentLayer];
    
    _shapeLayer = [CAShapeLayer layer];
    _shapeLayer.bounds = CGRectMake(0, 0, _contentWidth, _contentHeight);
    _shapeLayer.position = CGPointMake(_contentWidth/2, _contentHeight/2);
    _shapeLayer.backgroundColor = [UIColor clearColor].CGColor;
//    _shapeLayer.lineCap  = kCALineCapRound;
    //进行边界描绘 默认线宽为4px
    UIBezierPath * path = [UIBezierPath bezierPathWithArcCenter:_shapeLayer.position radius:_contentWidth/2-2 startAngle:-M_PI_2 endAngle:M_PI_2*3 clockwise:YES];
    _shapeLayer.path = path.CGPath;
    _shapeLayer.fillColor = [UIColor clearColor].CGColor;
    _shapeLayer.lineWidth = 4;
    _shapeLayer.strokeColor = [UIColor redColor].CGColor;
    //默认黄转橙转红的边界线 分别由两个gradLayer进行控制
    _gradLayer = [CALayer layer];
    _gradLayer.bounds = _contentLayer.bounds;
    _gradLayer.position = _contentLayer.position;
    _gradLayer.backgroundColor = [UIColor clearColor].CGColor;
    _gradLayerL = [CAGradientLayer layer];
    _gradLayerL.bounds = CGRectMake(0, 0, _contentWidth/2, _contentHeight);
    _gradLayerL.locations = @[@0.6];
    [_gradLayerL setColors:@[(id)[UIColor redColor].CGColor,(id)[UIColor orangeColor].CGColor]];
    _gradLayerL.position = CGPointMake(_gradLayerL.bounds.size.width/2, _gradLayerL.bounds.size.height/2);
   [_gradLayer addSublayer:_gradLayerL];
    _gradLayerR = [CAGradientLayer layer];
    _gradLayerR.locations = @[@0.6];
    _gradLayerR.bounds = CGRectMake(_contentWidth/2, 0, _contentWidth/2, _contentHeight);
    [_gradLayerR setColors:@[(id)[UIColor yellowColor].CGColor,(id)[UIColor orangeColor].CGColor]];
    _gradLayerR.position = CGPointMake(_gradLayerR.bounds.size.width/2+_contentWidth/2, _gradLayerR.bounds.size.height/2);
    [_gradLayer addSublayer:_gradLayerR];
    [_gradLayer setMask:_shapeLayer];
    [_contentLayer addSublayer:_gradLayer];
    
    
    //setter方法初始化
    _minLineColor = [UIColor yellowColor];
    _midLineColor = [UIColor orangeColor];
    _maxLineColor = [UIColor redColor];
    _lineTintColor = [UIColor grayColor];
    _progress = 1;
    _lineWidth = 4;
    _lineTintColor = [UIColor grayColor];
    _textColor = [UIColor orangeColor];
    _oldProgress = 1;
    //创建tiplabel
    [self creatTipLabel];
    _timer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 target:self selector:@selector(updateLabel) userInfo:nil repeats:YES];
    _timer.fireDate = [NSDate distantFuture];
   
}

-(void)removeFromSuperview{
    _timer.fireDate = [NSDate distantFuture];
    [_timer invalidate];
    _timer =nil;
    [super removeFromSuperview];
}
-(void)updateLabel{
    if (old<new) {
        old++;
        NSMutableAttributedString * attri = [[NSMutableAttributedString alloc]initWithString:[NSString stringWithFormat:@"%d%%",old]];
        [attri addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:22] range:NSMakeRange(0, attri.length-1)];
        [attri addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:15] range:NSMakeRange(attri.length-1, 1)];
        [attri addAttribute:NSForegroundColorAttributeName value:_textColor range:NSMakeRange(0, attri.length)];
        _tipLabel.attributedText = attri;
    }else if (old>new){
        old--;
        NSMutableAttributedString * attri = [[NSMutableAttributedString alloc]initWithString:[NSString stringWithFormat:@"%d%%",old]];
        [attri addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:22] range:NSMakeRange(0, attri.length-1)];
        [attri addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:15] range:NSMakeRange(attri.length-1, 1)];
        [attri addAttribute:NSForegroundColorAttributeName value:_textColor range:NSMakeRange(0, attri.length)];
        _tipLabel.attributedText = attri;
    }else{
        _timer.fireDate = [NSDate distantFuture];
    }
}
-(void)setMinLineColor:(UIColor *)minLineColor{
    _minLineColor = minLineColor;
    [_gradLayerR setColors:@[(id)_minLineColor.CGColor,(id)_midLineColor.CGColor]];
    [_gradLayerL setColors:@[(id)_maxLineColor.CGColor,(id)_midLineColor.CGColor]];
}
-(void)setMidLineColor:(UIColor *)midLineColor{
    _midLineColor = midLineColor;
    [_gradLayerR setColors:@[(id)_minLineColor.CGColor,(id)_midLineColor.CGColor]];
    [_gradLayerL setColors:@[(id)_maxLineColor.CGColor,(id)_midLineColor.CGColor]];
}
-(void)setMaxLineColor:(UIColor *)maxLineColor{
    _maxLineColor = maxLineColor;
    [_gradLayerR setColors:@[(id)_minLineColor.CGColor,(id)_midLineColor.CGColor]];
    [_gradLayerL setColors:@[(id)_maxLineColor.CGColor,(id)_midLineColor.CGColor]];
}
-(void)setTintColor:(UIColor *)tintColor{
    _lineTintColor = tintColor;
    _contentLayer.strokeColor = tintColor.CGColor;
}
-(void)setProgress:(CGFloat)progress{
    _oldProgress = _progress;
    _progress=progress;
    _shapeLayer.strokeStart = 0;
    _shapeLayer.strokeEnd = progress>1?1:progress;
    NSMutableAttributedString * attri ;
    if (progress==1) {
        attri = [[NSMutableAttributedString alloc]initWithString:@"100%"];
    }else{
        attri = [[NSMutableAttributedString alloc]initWithString:[NSString stringWithFormat:@"%2d%%",(int)(progress*100)]];
    }
    [attri addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:22] range:NSMakeRange(0, attri.length-1)];
    [attri addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:15] range:NSMakeRange(attri.length-1, 1)];
    [attri addAttribute:NSForegroundColorAttributeName value:_textColor range:NSMakeRange(0, attri.length)];
    _tipLabel.attributedText = attri;
}

-(void)setProgress:(CGFloat)progress animated:(BOOL)animated{
    _oldProgress = _progress;
    _progress = progress;
    old = (int)(_oldProgress*100);
    new = (int)(_progress*100);
    CABasicAnimation * ani = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    ani.toValue = progress>1?@1:@(progress);
    ani.duration = 0.3;
    ani.delegate=self;
    ani.fillMode=kCAFillModeForwards;
    ani.removedOnCompletion=NO;
    [_shapeLayer addAnimation:ani forKey:nil];
    _timer.fireDate = [NSDate distantPast];
    
}
- (void)dealloc
{
    
}
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    if (flag) {
        [_shapeLayer removeAllAnimations];
        _shapeLayer.strokeEnd = _progress>1?1:_progress;
    }
}
-(void)setLineWidth:(CGFloat)lineWidth{
    if (lineWidth<0.5) {
        lineWidth=0.5;
    }
    if (lineWidth>20) {
        lineWidth = 20;
    }
    _lineWidth = lineWidth;
    UIBezierPath * path = [UIBezierPath bezierPathWithArcCenter:_shapeLayer.position radius:_contentWidth/2-lineWidth/2 startAngle:-M_PI_2 endAngle:M_PI_2*3 clockwise:YES];
    _shapeLayer.path = path.CGPath;
    _shapeLayer.fillColor = [UIColor clearColor].CGColor;
    _shapeLayer.lineWidth = lineWidth;
    _shapeLayer.strokeColor = [UIColor redColor].CGColor;
    [_gradLayer setMask:_shapeLayer];
    UIBezierPath * pathT = [UIBezierPath bezierPathWithArcCenter:_contentLayer.position radius:_contentWidth/2-lineWidth/2 startAngle:-M_PI_2 endAngle:M_PI_2*3 clockwise:YES];
    _contentLayer.path = pathT.CGPath;
    _contentLayer.lineWidth = lineWidth;

}
-(void)setTextColor:(UIColor *)textColor{
    _textColor = textColor;
    NSMutableAttributedString * attr = [[NSMutableAttributedString alloc]initWithAttributedString:_tipLabel.attributedText];
    [attr addAttribute:NSForegroundColorAttributeName value:textColor range:NSMakeRange(0, attr.length)];
    _tipLabel.attributedText = attr;
}
-(void)creatTipLabel{
    _tipLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, sqrt(2)/2*(_contentWidth-_lineWidth*2), sqrt(2)/2*(_contentWidth-_lineWidth*2))];
    _tipLabel.center = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
    _tipLabel.backgroundColor = [UIColor clearColor];
    _tipLabel.textAlignment = NSTextAlignmentCenter;
    NSMutableAttributedString * attri = [[NSMutableAttributedString alloc]initWithString:@"100%"];
    [attri addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:22] range:NSMakeRange(0, 3)];
    [attri addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:15] range:NSMakeRange(3, 1)];
    [attri addAttribute:NSForegroundColorAttributeName value:[UIColor orangeColor] range:NSMakeRange(0, 4)];
    _tipLabel.attributedText = attri;
    [self addSubview:_tipLabel];
}
@end

专注技术,热爱生活,交流技术,也做朋友。

——珲少 QQ群:203317592