iOS 圆弧进度控件设计
zhyv
9年前
<h2>带动画渐进效果与颜色渐变的圆弧进度控件设计</h2> <p>今天帮朋友写了一个小巧的圆弧进度控件,控件十分简单,主要设计思路采用CAShapeLayer来创建控件圆弧形状,使用CAGradientLayer来进行颜色渐变的渲染,两者结合来创建出颜色渐变的圆弧进度条控件,关于进度动画采用CoreAnimation动画处理。控件进行了简洁的封装,提供了面向使用的接口,需要的朋友可以自取,Demo地址如下:</p> <p><a href="/misc/goto?guid=4959671034289606411" rel="nofollow,noindex">http://pan.baidu.com/s/1gfqDbtp </a> 。</p> <p>控件中主要提供了,改变进度条渐变颜色,圆弧进度条宽度,带动画效果的改变进度,改变进度百分比字体颜色等方法。效果是例如如下:</p> <p><img src="https://simg.open-open.com/show/741acd323d10528cda7ed67a2c2d4a0e.gif"></p> <p>改变字体颜色</p> <p><img src="https://simg.open-open.com/show/601bb95f2a33f756cf8ab66b436df394.gif"></p> <p>改变进度</p> <p><img src="https://simg.open-open.com/show/71265d30b98a412988c87bf096a488a1.gif"></p> <p>改变进度条颜色</p> <p><img src="https://simg.open-open.com/show/e0a20683f0db0b4e471c3d12bd00dbf2.gif"></p> <p>改变进度条宽度</p> <p>控件接口的设计:</p> <pre> <code class="language-objectivec">#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</code></pre> <p>实现方法如下:</p> <pre> <code class="language-objectivec">#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</code></pre>