公司最近要开发新版本了,其中有一个效果是环型进度条颜色渐变,查找了一些资料,打算把具体实现过程说一说。
效果图:
1、 使用的技术
pop
:用来实现文字变化的动态效果
CAShapeLayer
: 用来绘制背景圆环和进度圆环
CAGradientLayer
:渐变图层,添加渐变颜色2、自定义一个view,将进度作为属性与外界进行连接
#import <UIKit/UIKit.h>
@interface Circle : UIView
///项目进度
@property (nonatomic,assign) CGFloat progress;
@end
.m 实现过程
#import "Circle.h"
#import <POP.h>
#define SELF_WIDTH CGRectGetWidth(self.bounds)
#define SELF_HEIGHT CGRectGetHeight(self.bounds)
#define DEGREES_TO_RADOANS(x) (M_PI * (x) / 180.0) // 将角度转为弧度
#define Duration 3 //动画时长
#define LineWidth 8.0 //线宽
#define LittleLineWidth 2.0
#define LittleCycleScale 2.2 //小线圈的缩放倍数
@interface Circle ()
///进度条
@property (nonatomic,strong) CAShapeLayer *progressLayer;
///小进度条
@property (nonatomic,strong) CAShapeLayer *littleProgressLayer;
///背景条
@property (nonatomic,strong) CAShapeLayer *backgroundLayer;
///显示进度的label
@property (nonatomic,strong) UILabel *progressLabel;
///渐变色图层
@property (nonatomic,strong) CALayer *gradientLayer;
@end
@implementation Circle
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame: frame];
if (self) {
self.backgroundColor = [UIColor colorWithRed:38.0 / 255.0 green:130.0 / 255.0 blue:213.0 / 255.0 alpha:0.5];
[self setupLabel];
[self setupBackgroundLayer];
[self setupProgressLayer];
//默认0,我们需要从90°开始,所以将view旋转
self.transform = CGAffineTransformRotate(self.transform, -M_PI_2);
}
return self;
}
- (void)setProgress:(CGFloat)progress {
_progress = progress;
[self drawLineAnimation:self.progressLayer progress:progress];
[self drawLineAnimation:self.littleProgressLayer progress:progress];
//文字动态变化
POPBasicAnimation *anim = [POPBasicAnimation animation];
anim.duration = progress * Duration;
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
POPAnimatableProperty * prop = [POPAnimatableProperty propertyWithName:@"count" initializer:^(POPMutableAnimatableProperty *prop) {
// read value
prop.readBlock = ^(id obj, CGFloat values[]) {
values[0] = [[obj description] floatValue];
};
// write
prop.writeBlock = ^(id obj, const CGFloat values[]) {
[obj setText:[NSString stringWithFormat:@"%.0f%%",values[0]]];
};
//力学阈值
prop.threshold = 1;
}];
anim.property = prop;
anim.fromValue = @(0.0);
anim.toValue = @(progress * 100);
[self.progressLabel pop_addAnimation:anim forKey:@"count"];
}
/**
进度文字
*/
- (void)setupLabel {
self.progressLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, SELF_WIDTH - 20, 40)];
self.progressLabel.center = CGPointMake(SELF_WIDTH / 2, SELF_HEIGHT / 2);
self.progressLabel.textAlignment = NSTextAlignmentCenter;
self.progressLabel.font = [UIFont systemFontOfSize:15];
self.progressLabel.transform = CGAffineTransformRotate(self.progressLabel.transform, M_PI_2);
[self addSubview:self.progressLabel];
}
/**
设置进度条
*/
- (void)setupProgressLayer {
self.progressLayer = [self generateLayerWhitLineWidth:LineWidth cgrect:CGRectMake(LineWidth / 2, LineWidth / 2, self.bounds.size.width - LineWidth, self.bounds.size.height - LineWidth)];
self.littleProgressLayer = [self generateLayerWhitLineWidth:LittleCycleScale cgrect:CGRectMake(LineWidth * LittleCycleScale, LineWidth * LittleCycleScale, self.bounds.size.width - LineWidth * LittleCycleScale * 2, self.bounds.size.height - LineWidth * LittleCycleScale * 2)];
[self creatGradientWithShapeLayer:self.progressLayer];
[self creatGradientWithShapeLayer:self.littleProgressLayer];
}
///生成渐变色
- (void)creatGradientWithShapeLayer:(CAShapeLayer *)shapelayer {
//生成渐变色
self.gradientLayer = [CALayer layer];
self.gradientLayer.frame = self.bounds;
[self.layer addSublayer:self.gradientLayer];
//渐变色
CAGradientLayer *contentLayer = [CAGradientLayer layer];
contentLayer.frame = CGRectMake(0, 0, self.bounds.size.width , self.bounds.size.height); // 分段设置渐变色
// leftLayer.locations = @[@0, @0.3,@0.6, @1];
contentLayer.colors = @[(id)[UIColor greenColor].CGColor, (id)[UIColor blueColor].CGColor];
[self.gradientLayer addSublayer:contentLayer];
[self.gradientLayer setMask:shapelayer];
shapelayer.strokeColor = [UIColor whiteColor].CGColor;
}
/**
设置环型背景
*/
- (void)setupBackgroundLayer {
self.backgroundLayer = [self generateLayerWhitLineWidth:LineWidth cgrect:CGRectMake(LineWidth / 2, LineWidth / 2, self.bounds.size.width - LineWidth , self.bounds.size.height - LineWidth)];
// bgLayer.position = self.center;//居中显示
self.backgroundLayer.strokeColor = [UIColor grayColor].CGColor;//线条颜色
self.backgroundLayer.strokeStart = 0.f;//路径开始位置
self.backgroundLayer.strokeEnd = 1.f;//路径结束位置
}
/**
环型背景和进度条(包括小进度条)可以封装成同一个方法
@return 环形条
*/
- (CAShapeLayer *)generateLayerWhitLineWidth:(CGFloat)lineWidth cgrect:(CGRect)cgrect {
CAShapeLayer *layer = [CAShapeLayer layer];
layer.frame = self.bounds;
layer.lineCap = kCALineCapRound;//线样式
layer.lineWidth = lineWidth;
layer.fillColor = [UIColor clearColor].CGColor;//填充色
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:cgrect];
layer.path = path.CGPath;
[self.layer addSublayer:layer];
return layer;
}
/**
设置动画效果
@param layer 进度条layer
@param progress 设置的进度
*/
-(void)drawLineAnimation:(CALayer*)layer progress:(CGFloat)progress{
POPBasicAnimation *bas = [POPBasicAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeEnd];
//动画时间
bas.duration = progress * Duration;
//控制动画节奏
bas.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
bas.delegate=self;
bas.removedOnCompletion = NO;
bas.fromValue = @(0);
bas.toValue = [NSNumber numberWithFloat:self.progress];
[layer pop_addAnimation:bas forKey:@""];
}
@end
只要在控制器中初始化Circle
,并添加到view中就可以实现上面的效果了。至于渐变颜色及线宽可以根据项目进行设置。