背景:
最近项目需要加载网络图片的时候显示圆形进度,提高用户体验,研究了一下做个记录。
思路
实现起来其实很简单。
1、创建UIImageView的分类,设置时直接调用分类方法。
2、借助SDWebImage的方法,拿到加载进度。
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
3、自定义进度视图,绘制进度。
源码
UIImageView分类
#import "UIImageView+WebCache.h"
#import <SDWebImage/UIImageView+WebCache.h>
#import "CustomProgressView.h"
@interface UIImageView (ProgressView)
- (void)sd_setImageWithURL:(NSURL *)url usingProgressView:(CustomProgressView *)progressView;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder usingProgressView:(CustomProgressView *)progressView;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options usingProgressView:(CustomProgressView *)progressView;
- (void)sd_setImageWithURL:(NSURL *)url completed:(SDExternalCompletionBlock)completedBlock usingProgressView:(CustomProgressView *)progressView;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDExternalCompletionBlock)completedBlock usingProgressView:(CustomProgressView *)progressView;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDExternalCompletionBlock)completedBlock usingProgressView:(CustomProgressView *)progressView;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDExternalCompletionBlock)completedBlock usingProgressView:(CustomProgressView *)progressView;
- (void)removeProgressView;
@end
#import "UIImageView+ProgressView.h"
#define TAG_PROGRESS_VIEW 149462
@implementation UIImageView (ProgressView)
- (void)addProgressView:(CustomProgressView *)progressView {
CustomProgressView *existingProgressView = (CustomProgressView *)[self viewWithTag:TAG_PROGRESS_VIEW];
if (!existingProgressView) {
if (!progressView) {
progressView = [[CustomProgressView alloc] initWithFrame:self.frame];
progressView.backgroundColor = [UIColor grayColor];
}
progressView.tag = TAG_PROGRESS_VIEW;
progressView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin;
float width = progressView.frame.size.width;
float height = progressView.frame.size.height;
float x = (self.frame.size.width / 2.0) - width/2;
float y = (self.frame.size.height / 2.0) - height/2;
progressView.frame = CGRectMake(x, y, width, height);
[self addSubview:progressView];
}
}
- (void)updateProgress:(CGFloat)progress {
CustomProgressView *progressView = (CustomProgressView *)[self viewWithTag:TAG_PROGRESS_VIEW];
if (progressView) {
progressView.progressValue = progress;
}
}
- (void)removeProgressView {
CustomProgressView *progressView = (CustomProgressView *)[self viewWithTag:TAG_PROGRESS_VIEW];
if (progressView) {
[progressView removeFromSuperview];
}
}
- (void)sd_setImageWithURL:(NSURL *)url usingProgressView:(CustomProgressView *)progressView {
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil usingProgressView:progressView];
}
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder usingProgressView:(CustomProgressView *)progressView {
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil usingProgressView:progressView];
}
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options usingProgressView:(CustomProgressView *)progressView{
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil usingProgressView:progressView];
}
- (void)sd_setImageWithURL:(NSURL *)url completed:(SDExternalCompletionBlock)completedBlock usingProgressView:(CustomProgressView *)progressView {
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock usingProgressView:progressView];
}
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDExternalCompletionBlock)completedBlock usingProgressView:(CustomProgressView *)progressView {
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock usingProgressView:progressView];
}
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDExternalCompletionBlock)completedBlock usingProgressView:(CustomProgressView *)progressView {
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock usingProgressView:progressView];
}
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDExternalCompletionBlock)completedBlock usingProgressView:(CustomProgressView *)progressView {
[self addProgressView:progressView];
__weak typeof(self) weakSelf = self;
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
CGFloat progress = ((CGFloat)receivedSize / (CGFloat)expectedSize);
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf updateProgress:progress];
});
if (progressBlock) {
progressBlock(receivedSize, expectedSize, url);
}
} completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
[weakSelf removeProgressView];
if (completedBlock) {
completedBlock(image, error, cacheType, imageURL);
}
}];
}
@end
进度条视图
#import <UIKit/UIKit.h>
@interface CustomProgressView : UIView
@property (nonatomic, assign) CGFloat progressValue;
@end
#import "CustomProgressView.h"
@interface CustomProgressView ()
@property (nonatomic, strong) UILabel* progressLabel;
@end
@implementation CustomProgressView
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
-(UILabel *)progressLabel {
if (!_progressLabel) {
_progressLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
[self addSubview:_progressLabel];
}
return _progressLabel;
}
-(void)layoutSubviews {
self.progressLabel.center = self.center;
}
- (void)setProgressValue:(CGFloat)progressValue
{
_progressValue = progressValue;
// 设置label的文字
self.progressLabel.text = [NSString stringWithFormat:@"%.2f%%", progressValue * 100];
NSLog(@"self.progressLabel - %f",progressValue);
// 重绘
[self setNeedsDisplay];
}
-(void)drawRect:(CGRect)rect {
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:self.center radius:self.frame.size.width < self.frame.size.height ? self.frame.size.width * 0.3 : self.frame.size.height * 0.3 startAngle:-M_PI_2 endAngle:2 * M_PI * self.progressValue - M_PI_2 clockwise:1];
[path setLineWidth:5];
[[UIColor orangeColor] setStroke];
// 填充
[path stroke];
}
@end
调用方法
[self.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://static1.beesns.cn/user/avatar/20190812/568deb487b8f5575b19a056e501d7533.jpg"] placeholderImage:nil options:SDWebImageCacheMemoryOnly usingProgressView:nil];
补充
画进度的时候根据进度绘制,调用[self setNeedsDisplay];会自动调用
-(void)drawRect:(CGRect)rect;