美文网首页
iOS 自定义下载进度按钮

iOS 自定义下载进度按钮

作者: JohnayXiao | 来源:发表于2018-09-03 15:31 被阅读232次

创建

 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

相关文章

网友评论

      本文标题:iOS 自定义下载进度按钮

      本文链接:https://www.haomeiwen.com/subject/sgzbwftx.html