//
// CCProgressView.h
// Demo
//
// Created by leao on 2017/8/7.
// Copyright © 2017年 zaodao. All rights reserved.
//
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, CCProgressViewStyle) {
CCProgressViewStyleCircle, // 圆形进度条
CCProgressViewStyleBar, // 条形进度条
CCProgressViewStyleDefault = CCProgressViewStyleCircle,
};
@interface CCProgressView : UIView
@property(nonatomic, assign, setter=setProgress:) CGFloat progress; // 0.0 ~ 1.0
@property(nonatomic, assign) CCProgressViewStyle progressViewStyle; // 进度条style
@property(nonatomic, strong) UIColor *trackTintColor; // 进度条背景色
@property(nonatomic, strong) UIColor *progressTintColor; // 进度条颜色
@property(nonatomic, strong) UIColor *progressFullTintColor; // 进度完成时progressTint的颜色
@property(nonatomic, assign) CGFloat lineWidth; // 绘制progress宽度 default: 10
@property(nonatomic, assign) CGFloat trackerWidth; // 绘制progress宽度 default: 10
// CCProgressViewStyleCircle 有效
@property(nonatomic, strong) UIColor *fillColor; // 中心颜色
@property(nonatomic, assign) BOOL clockwise; // 是否是顺时针 default: YES
@property(nonatomic, assign) CGFloat startAngle; // 进度条开始angle, default: -M_PI/2.0
@property (nonatomic, strong) UIButton *centerBtn; // 记录进度的Label
@property (nonatomic, strong) UIColor *labelbackgroundColor; // Label的背景色 默认clearColor
@property (nonatomic, strong) UIColor *textColor; // Label的字体颜色 默认黑色
@property (nonatomic, strong) UIFont *textFont; // Label的字体大小 默认15
- (void)setProgress:(CGFloat)progress;
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated;
@end
//
// CCProgressView.m
// Demo
//
// Created by leao on 2017/8/7.
// Copyright © 2017年 zaodao. All rights reserved.
//
#import "CCProgressView.h"
#import <pop/POP.h>
#import <objc/runtime.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
#define kCCProgressFillColor [UIColor clearColor]
#define kCCProgressTintColor RGBCOLOR(214, 88, 45)
#define kCCTrackTintColor RGBCOLOR(243, 212, 187)
#define PROGRESS_WIDTH self.frame.size.width
#define PROGRESS_HEIGHT self.frame.size.height
#define kAnimTimeInterval 2
@interface CCProgressView ()
@property(nonatomic, strong) CAShapeLayer *trackLayer;
@property(nonatomic, strong) CAShapeLayer *progressLayer;
@end
@implementation CCProgressView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self initSubviews];
}
return self;
}
- (instancetype)init
{
self = [super init];
if (self) {
[self initSubviews];
}
return self;
}
#pragma mark - private
- (void)initSubviews
{
_progressViewStyle = CCProgressViewStyleDefault;
_progressTintColor = kCCProgressTintColor;
_trackTintColor = kCCTrackTintColor;
_lineWidth = 10;
_trackerWidth = 10;
_fillColor = kCCProgressFillColor;
_clockwise = YES;
_startAngle = - M_PI / 2.0;
self.backgroundColor = [UIColor clearColor];
self.trackLayer = [CAShapeLayer layer];
self.trackLayer.lineCap = kCALineCapButt;
self.trackLayer.lineJoin = kCALineCapButt;
self.trackLayer.lineWidth = _lineWidth;
self.trackLayer.fillColor = nil;
self.trackLayer.strokeColor = _trackTintColor.CGColor;
self.trackLayer.frame = self.bounds;
[self.layer addSublayer:self.trackLayer];
self.progressLayer = [CAShapeLayer layer];
self.progressLayer.lineCap = kCALineCapButt;
self.progressLayer.lineJoin = kCALineCapButt;
self.progressLayer.lineWidth = _trackerWidth;
self.progressLayer.fillColor = _fillColor.CGColor;
self.progressLayer.strokeColor = _progressTintColor.CGColor;
self.progressLayer.frame = self.bounds;
[self.layer addSublayer:self.progressLayer];
self.progressLayer.strokeEnd = 0.0;
[self addSubview:self.centerBtn];
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self updateLayerPath];
}
#pragma mark - private
- (UIButton *)centerBtn
{
if(!_centerBtn)
{
_centerBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, PROGRESS_WIDTH - 14, PROGRESS_HEIGHT - 14)];
_centerBtn.center = CGPointMake(PROGRESS_WIDTH/2, PROGRESS_HEIGHT/2);
_centerBtn.titleLabel.textAlignment = NSTextAlignmentCenter;
_centerBtn.layer.cornerRadius = _centerBtn.width/2;
_centerBtn.backgroundColor = RGBCOLOR(246, 227, 204);
_centerBtn.titleLabel.adjustsFontSizeToFitWidth = YES;
_centerBtn.userInteractionEnabled = NO;
_centerBtn.layer.masksToBounds = YES;
}
return _centerBtn;
}
- (void)updateLayerPath
{
if (_progressViewStyle == CCProgressViewStyleCircle) {
self.trackLayer.frame = self.bounds;
self.progressLayer.frame = self.bounds;
CGFloat radius = CGRectGetWidth(self.frame) > CGRectGetHeight(self.frame) ?
(CGRectGetHeight(self.frame) - _lineWidth) / 2.0 : (CGRectGetWidth(self.frame) - _lineWidth) / 2.0;
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithArcCenter:self.progressLayer.position radius:radius startAngle:_startAngle endAngle:_clockwise ? _startAngle + 2 * M_PI : _startAngle - 2 * M_PI clockwise:_clockwise];
self.trackLayer.path = bezierPath.CGPath;
self.progressLayer.path = bezierPath.CGPath;
} else {
self.trackLayer.frame = CGRectMake(0, (CGRectGetHeight(self.frame) - _lineWidth) / 2.0, CGRectGetWidth(self.frame), _lineWidth);
self.progressLayer.frame = self.trackLayer.frame;
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(0, self.progressLayer.position.y)];
[bezierPath addLineToPoint:CGPointMake(CGRectGetWidth(self.frame), self.progressLayer.position.y)];
self.trackLayer.path = bezierPath.CGPath;
self.progressLayer.path = bezierPath.CGPath;
}
}
#pragma mark - setter
- (void)setTrackTintColor:(UIColor *)trackTintColor
{
_trackTintColor = trackTintColor;
self.trackLayer.strokeColor = trackTintColor.CGColor;
}
- (void)setProgressTintColor:(UIColor *)progressTintColor
{
_progressTintColor = progressTintColor;
self.progressLayer.strokeColor = progressTintColor.CGColor;
}
- (void)setProgressFullTintColor:(UIColor *)progressFullTintColor
{
_progressFullTintColor = progressFullTintColor;
if (self.progressLayer.strokeEnd >= 1.0) {
self.progressLayer.strokeEnd = 1.0;
self.progressLayer.strokeColor = _progressFullTintColor.CGColor;
}
}
- (void)setLineWidth:(CGFloat)lineWidth
{
_lineWidth = lineWidth;
// self.trackLayer.lineWidth = lineWidth;
self.progressLayer.lineWidth = lineWidth;
if (_progressViewStyle != CCProgressViewStyleCircle) {
[self updateLayerPath];
}
}
- (void)setTrackerWidth:(CGFloat)trackerWidth {
_trackerWidth = trackerWidth;
self.trackLayer.lineWidth = _trackerWidth;
if (_progressViewStyle != CCProgressViewStyleCircle) {
[self updateLayerPath];
}
}
#pragma mark - setter (CCProgressViewStyleCircle)
- (void)setFillColor:(UIColor *)fillColor
{
_fillColor = fillColor;
self.progressLayer.fillColor = fillColor.CGColor;
}
- (void)setClockwise:(BOOL)clockwise
{
_clockwise = clockwise;
[self updateLayerPath];
}
- (void)setStartAngle:(CGFloat)startAngle
{
_startAngle = startAngle;
[self updateLayerPath];
}
- (void)setProgress:(CGFloat)progress
{
[self setProgress:progress animated:NO];
}
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated
{
if (animated) { // 这里的动画可以直接使用CABasicAnimation
POPBasicAnimation *basicAnim = [POPBasicAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeEnd];
if (basicAnim) {
basicAnim.duration = kAnimTimeInterval;
basicAnim.toValue = @(progress);
} else {
basicAnim = [POPBasicAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeEnd];
basicAnim.fromValue = @(self.progressLayer.strokeEnd);
basicAnim.toValue = @(progress);
basicAnim.duration = 4 * kAnimTimeInterval;
basicAnim.removedOnCompletion = YES;
}
@weakify(self);
basicAnim.completionBlock = ^(POPAnimation *anim, BOOL finished) {
@strongify(self);
POPPropertyAnimation *basicAnim = (POPPropertyAnimation *)anim;
self.progressLayer.strokeEnd = [basicAnim.toValue doubleValue];
if (self.progressLayer.strokeEnd >= 1.0 && _progressFullTintColor) {
self.progressLayer.strokeEnd = 1.0;
self.progressLayer.strokeColor = _progressFullTintColor.CGColor;
}
};
[self.progressLayer pop_addAnimation:basicAnim forKey:kPOPShapeLayerStrokeEnd];
} else {
self.progressLayer.strokeEnd = progress;
if (self.progressLayer.strokeEnd >= 1.0 && _progressFullTintColor) {
self.progressLayer.strokeEnd = 1.0;
self.progressLayer.strokeColor = _progressFullTintColor.CGColor;
}
}
}
@end