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>