创建
XJDownloadIndicator *closedIndicator = [[XJDownloadIndicator alloc] initWithFrame:CGRectMake(0,0,40,40)];
[closedIndicator setBackgroundColor:[UIColor clearColor]];
self.downloadBtn = closedIndicator;
WeakSelf;
self.downloadBtn.clickBlock = ^() {
[weakSelf downloadBtnClick];
};
[self.contentView addSubview:self.downloadBtn];
更新下载进度
[self.downloadBtn.picButton setImage:[[UIImage imageNamed:@"icon_download2"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
[self.downloadBtn setStrokeColor:themeColor()];
[self.downloadBtn setStrokeBackgroundColor:techLineColor()];
[self.downloadBtn updateWithTotalBytes:self.receipt.totalBytesExpectedToWrite downloadedBytes:self.receipt.totalBytesWritten];
.h文件
#import <UIKit/UIKit.h>
@interface XJDownloadIndicator : UIView
// used to stroke the covering slice (default: (kRMClosedIndicator = white), (kRMMixedIndictor = white))
@property(nonatomic, strong)UIColor *strokeColor;
// used to stroke the background path the covering slice (default: (kRMClosedIndicator = gray))
@property(nonatomic, strong)UIColor *strokeBackgroundColor;
@property(nonatomic, strong)UIButton *picButton;
@property(nonatomic, copy) NSString *identifierStr;
@property(nonatomic, copy) void (^clickBlock)();
// update the downloadIndicator
- (void)updateWithTotalBytes:(CGFloat)bytes downloadedBytes:(CGFloat)downloadedBytes;
@end
.m文件
#import "XJDownloadIndicator.h"
@interface XJDownloadIndicator()
// this contains list of paths to be animated through
@property(nonatomic, strong)NSMutableArray *paths;
// this is the layer used for animation
@property(nonatomic, strong)CAShapeLayer *animatingLayer;
// this applies to the covering stroke (default: 2)
@property(nonatomic, assign)CGFloat coverWidth;
// the last updatedPath
@property(nonatomic, strong)UIBezierPath *lastUpdatedPath;
@property(nonatomic, assign)CGFloat lastSourceAngle;
// this the animation duration (default: 0.5)
@property(nonatomic, assign)CGFloat animationDuration;
// this value should be 0 to 0.5 (default: (kRMFilledIndicator = 0.5), (kRMMixedIndictor = 0.4))
@property(nonatomic, assign)CGFloat radiusPercent;
@end
@implementation XJDownloadIndicator
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.radiusPercent = 0.25;
_animatingLayer = [CAShapeLayer layer];
_strokeColor = [UIColor clearColor];
_strokeBackgroundColor = [UIColor clearColor];
_coverWidth = 1.0;
self.picButton = [[UIButton alloc] initWithFrame:self.bounds];
[self.picButton addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.picButton];
_animatingLayer.frame = self.bounds;
[self.layer addSublayer:_animatingLayer];
// path array
_paths = [NSMutableArray array];
// animation duration
_animationDuration = 0.5;
[self loadIndicator];
//
// POST_NOTIFICATION_WITH_INFO(@"refreshDownloadBtnProgress", (@{@"itentifier":targetURL.absoluteString,@"expectedSize":@(expectedSize),@"receivedSize":@(receivedSize)}));
ADD_NOTIFICATION_WITH_SEL_AND_NAME(@selector(refreshDownloadBtnProgress:), @"refreshDownloadBtnProgress")
}
return self;
}
- (void)refreshDownloadBtnProgress:(NSNotification *)ntf {
NSDictionary *dic = ntf.userInfo;
// xjLog(@"--------------------------------");
// xjLog(self.identifierStr);
// xjLog(dic[@"itentifier"]);
// xjLog(@"--------------------------------");
if ([self.identifierStr isEqualToString:dic[@"itentifier"]]) {
// xjLog(@"++++++++++++++++++++++++++++++++++");
// xjLog(self.identifierStr);
// xjLog(dic[@"itentifier"]);
// xjLog(@"++++++++++++++++++++++++++++++++++");
[self updateWithTotalBytes:[dic[@"expectedSize"] floatValue] downloadedBytes:[dic[@"receivedSize"] floatValue]];
}
}
- (void)btnClick {
self.clickBlock ? self.clickBlock() : nil;
}
- (void)loadIndicator
{
// set the initial Path
CGPoint center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
UIBezierPath *initialPath = [UIBezierPath bezierPath]; //empty path
// [self setNeedsDisplay];
[initialPath addArcWithCenter:center radius:(MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))) startAngle:degreeToRadian(-90) endAngle:degreeToRadian(-90) clockwise:YES]; //add the arc
_animatingLayer.path = initialPath.CGPath;
_animatingLayer.strokeColor = _strokeColor.CGColor;
_animatingLayer.fillColor = [UIColor clearColor].CGColor;
_animatingLayer.lineWidth = _coverWidth;
self.lastSourceAngle = degreeToRadian(-90);
}
#pragma mark - Helper Methods
- (NSArray *)keyframePathsWithDuration:(CGFloat)duration lastUpdatedAngle:(CGFloat)lastUpdatedAngle newAngle:(CGFloat)newAngle radius:(CGFloat)radius
{
NSUInteger frameCount = ceil(duration * 60);
NSMutableArray *array = [NSMutableArray arrayWithCapacity:frameCount + 1];
for (int frame = 0; frame <= frameCount; frame++)
{
CGFloat startAngle = degreeToRadian(-90);
CGFloat endAngle = lastUpdatedAngle + (((newAngle - lastUpdatedAngle) * frame) / frameCount);
[array addObject:(id)([self pathWithStartAngle:startAngle endAngle:endAngle radius:radius].CGPath)];
}
return [NSArray arrayWithArray:array];
}
- (UIBezierPath *)pathWithStartAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle radius:(CGFloat)radius
{
BOOL clockwise = startAngle < endAngle;
UIBezierPath *path = [UIBezierPath bezierPath];
CGPoint center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
[path addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:clockwise];
return path;
}
//当设置描绘背景颜色时调用drawRect方法
- (void)setStrokeBackgroundColor:(UIColor *)strokeBackgroundColor {
_strokeBackgroundColor = strokeBackgroundColor;
_animatingLayer.strokeColor = _strokeColor.CGColor;
[self setNeedsDisplay];
}
//此方法初始时调一次,之后用[self setNeedsDisplay]调用
- (void)drawRect:(CGRect)rect
{
CGFloat radius = (MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)) * _radiusPercent) - self.coverWidth;
CGPoint center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
UIBezierPath *coverPath = [UIBezierPath bezierPath]; //empty path
[coverPath setLineWidth:_coverWidth];
[coverPath addArcWithCenter:center radius:radius startAngle:0 endAngle:2*M_PI clockwise:YES]; //add the arc
[_strokeBackgroundColor set];
[coverPath stroke];
}
#pragma mark - update indicator
- (void)updateWithTotalBytes:(CGFloat)bytes downloadedBytes:(CGFloat)downloadedBytes
{
_lastUpdatedPath = [UIBezierPath bezierPathWithCGPath:_animatingLayer.path];
[_paths removeAllObjects];
CGFloat destinationAngle = [self destinationAngleForRatio:(downloadedBytes/bytes)];
CGFloat radius = (MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)) * _radiusPercent) - self.coverWidth;
[_paths addObjectsFromArray:[self keyframePathsWithDuration:self.animationDuration lastUpdatedAngle:self.lastSourceAngle newAngle:destinationAngle radius:radius]];
_animatingLayer.path = (__bridge CGPathRef)((id)_paths[(_paths.count -1)]);
self.lastSourceAngle = destinationAngle;
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"path"];
[pathAnimation setValues:_paths];
[pathAnimation setDuration:self.animationDuration];
[pathAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
[pathAnimation setRemovedOnCompletion:YES];
[_animatingLayer addAnimation:pathAnimation forKey:@"path"];
}
- (CGFloat)destinationAngleForRatio:(CGFloat)ratio
{
return (degreeToRadian((360*ratio) - 90));
}
float degreeToRadian(float degree)
{
return ((degree * M_PI)/180.0f);
}
- (void)dealloc {
REMOVE_ALL_OBSERVERS(self);
NSLog(@"%s", __func__);
}
@end
网友评论