iOS 圓弧進度控件設計
帶動畫漸進效果與顏色漸變的圓弧進度控件設計
今天幫朋友寫了一個小巧的圓弧進度控件,控件十分簡單,主要設計思路采用CAShapeLayer來創建控件圓弧形狀,使用CAGradientLayer來進行顏色漸變的渲染,兩者結合來創建出顏色漸變的圓弧進度條控件,關于進度動畫采用CoreAnimation動畫處理。控件進行了簡潔的封裝,提供了面向使用的接口,需要的朋友可以自取,Demo地址如下:
http://pan.baidu.com/s/1gfqDbtp 。
控件中主要提供了,改變進度條漸變顏色,圓弧進度條寬度,帶動畫效果的改變進度,改變進度百分比字體顏色等方法。效果是例如如下:
改變字體顏色
改變進度
改變進度條顏色
改變進度條寬度
控件接口的設計:
#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>
實現方法如下:
#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_23 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_23 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)(progress100)]];
}
[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)(_oldProgress100);
new = (int)(_progress100);
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_23 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-_lineWidth2), sqrt(2)/2(_contentWidth-_lineWidth2))];
_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>