mirror of
https://github.com/wu736139669/UIImageView-Reload.git
synced 2026-08-05 06:23:35 +00:00
添加文件
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// UIImageView+Reloading.h
|
||||||
|
// XiaoYu
|
||||||
|
// 可以显示进度,还可以失败重新下载
|
||||||
|
// Created by xmfish on 14-8-21.
|
||||||
|
// Copyright (c) 2014年 Benson. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "UIImageView+WebCache.h"
|
||||||
|
typedef NS_ENUM(NSInteger, LKImageViewStatus){
|
||||||
|
LKImageViewStatusNone = 0,
|
||||||
|
LKImageViewStatusLoaded = 1,
|
||||||
|
LKImageViewStatusLoading = 2,
|
||||||
|
LKImageViewStatusFail = 3
|
||||||
|
};
|
||||||
|
@interface UIImageView(Reloading)
|
||||||
|
//加载的图片 url地址 可以是 NSString 或 NSURL
|
||||||
|
@property(copy, nonatomic) id imageURL;
|
||||||
|
|
||||||
|
//这个不会设置 image 只会保存ImageURL
|
||||||
|
- (void)setImageURLFromCache:(id)imageURL;
|
||||||
|
|
||||||
|
//当前状态
|
||||||
|
@property LKImageViewStatus status;
|
||||||
|
|
||||||
|
//图片点击事件 不用再手动添加UITapGestureRecognizer
|
||||||
|
@property(copy, nonatomic) void(^onTouchTapBlock)(UIImageView *imageView);
|
||||||
|
|
||||||
|
//重新加载图片
|
||||||
|
- (void)reloadImageURL;
|
||||||
|
@end
|
||||||
@@ -0,0 +1,334 @@
|
|||||||
|
//
|
||||||
|
// UIImageView+Reloading.m
|
||||||
|
// XiaoYu
|
||||||
|
//
|
||||||
|
// Created by xmfish on 14-8-21.
|
||||||
|
// Copyright (c) 2014年 Benson. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "UIImageView+Reloading.h"
|
||||||
|
|
||||||
|
#import <execinfo.h>
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
#import <objc/message.h>
|
||||||
|
|
||||||
|
@implementation NSObject (Swizzle)
|
||||||
|
|
||||||
|
|
||||||
|
+ (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_ {
|
||||||
|
|
||||||
|
Method origMethod = class_getInstanceMethod(self, origSel_);
|
||||||
|
if (!origMethod) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
Method altMethod = class_getInstanceMethod(self, altSel_);
|
||||||
|
if (!altMethod) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
class_addMethod(self,
|
||||||
|
origSel_,
|
||||||
|
class_getMethodImplementation(self, origSel_),
|
||||||
|
method_getTypeEncoding(origMethod));
|
||||||
|
class_addMethod(self,
|
||||||
|
altSel_,
|
||||||
|
class_getMethodImplementation(self, altSel_),
|
||||||
|
method_getTypeEncoding(altMethod));
|
||||||
|
|
||||||
|
method_exchangeImplementations(class_getInstanceMethod(self, origSel_), class_getInstanceMethod(self, altSel_));
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_ {
|
||||||
|
return [object_getClass((id)self) jr_swizzleMethod:origSel_ withMethod:altSel_ error:error_];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
static char imageURLKey;
|
||||||
|
static char imageStatusKey;
|
||||||
|
static char imageTapEventKey;
|
||||||
|
static char imageOriginalModelKey;
|
||||||
|
@implementation UIImageView (SY)
|
||||||
|
+ (void)load
|
||||||
|
{
|
||||||
|
[UIImageView jr_swizzleMethod:@selector(cancelCurrentImageLoad) withMethod:@selector(sy_cancelCurrentImageLoad) error:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIButton *)sy_progressView:(BOOL)isCreate
|
||||||
|
{
|
||||||
|
static char imageProgressKey;
|
||||||
|
UIButton *progressView = objc_getAssociatedObject(self, &imageProgressKey);
|
||||||
|
if (isCreate)
|
||||||
|
{
|
||||||
|
if (progressView == nil)
|
||||||
|
{
|
||||||
|
progressView = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
|
progressView.frame = self.bounds;
|
||||||
|
progressView.hidden = YES;
|
||||||
|
progressView.backgroundColor = [UIColor clearColor];
|
||||||
|
[progressView setTitle:@"点击加载图片" forState:UIControlStateNormal];
|
||||||
|
[progressView setTitle:@"图片加载中" forState:UIControlStateDisabled];
|
||||||
|
progressView.titleLabel.shadowColor = [UIColor whiteColor];
|
||||||
|
progressView.titleLabel.shadowOffset = CGSizeMake(1, 1);
|
||||||
|
[progressView setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
|
||||||
|
[progressView setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
|
||||||
|
progressView.titleLabel.adjustsFontSizeToFitWidth = YES;
|
||||||
|
CGSize size = CGSizeMake(progressView.frame.size.width,2000);
|
||||||
|
CGSize labelsize = [progressView.titleLabel.text sizeWithFont:progressView.titleLabel.font constrainedToSize:size lineBreakMode:NSLineBreakByCharWrapping];
|
||||||
|
progressView.frame = CGRectMake(0.0, 0.0, labelsize.width, labelsize.height);
|
||||||
|
progressView.center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
|
||||||
|
[progressView addTarget:self action:@selector(reloadImageURL) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
progressView.enabled = NO;
|
||||||
|
objc_setAssociatedObject(self, &imageProgressKey, progressView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
__weak UIImageView* wself = self;
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[wself addSubview:progressView];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return progressView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIViewContentMode)originalViewContentMode
|
||||||
|
{
|
||||||
|
NSNumber *value = objc_getAssociatedObject(self, &imageOriginalModelKey);
|
||||||
|
int mode = -1;
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
mode = [value intValue];
|
||||||
|
}
|
||||||
|
if (mode < 0 || mode > UIViewContentModeBottomRight)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setOriginalViewContentMode:(UIViewContentMode)originalViewContentMode
|
||||||
|
{
|
||||||
|
NSNumber *value = [[NSNumber alloc] initWithInt:originalViewContentMode];
|
||||||
|
objc_setAssociatedObject(self, &imageOriginalModelKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (LKImageViewStatus)status
|
||||||
|
{
|
||||||
|
NSNumber *value = objc_getAssociatedObject(self, &imageStatusKey);
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
return [value intValue];
|
||||||
|
}
|
||||||
|
return LKImageViewStatusNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setStatus:(LKImageViewStatus)status
|
||||||
|
{
|
||||||
|
objc_setAssociatedObject(self, &imageStatusKey, @(status), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
|
}
|
||||||
|
- (void)setImageURLFromCache:(id)imageURL
|
||||||
|
{
|
||||||
|
[self sy_loadTapEvent];
|
||||||
|
self.status = LKImageViewStatusLoaded;
|
||||||
|
objc_setAssociatedObject(self, &imageURLKey, imageURL, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setImageURL:(id)imageURL
|
||||||
|
{
|
||||||
|
[self sy_loadTapEvent];
|
||||||
|
objc_setAssociatedObject(self, &imageURLKey, imageURL, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||||
|
if (imageURL)
|
||||||
|
{
|
||||||
|
[self reloadImageURL];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[self sy_cancelCurrentImageLoad];
|
||||||
|
self.image = nil;
|
||||||
|
self.backgroundColor = [UIColor colorWithRed:233/255.0 green:228/255.0 blue:223/255.0 alpha:1];
|
||||||
|
self.status = LKImageViewStatusNone;
|
||||||
|
|
||||||
|
UIButton *pv = [self sy_progressView:NO];
|
||||||
|
[pv removeFromSuperview];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sy_loadTapEvent
|
||||||
|
{
|
||||||
|
static char tapEventLoadedKey;
|
||||||
|
id loaded = objc_getAssociatedObject(self, &tapEventLoadedKey);
|
||||||
|
if (loaded == nil)
|
||||||
|
{
|
||||||
|
self.userInteractionEnabled = YES;
|
||||||
|
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sy_handleTapEvent:)];
|
||||||
|
[self addGestureRecognizer:tap];
|
||||||
|
objc_setAssociatedObject(self, &tapEventLoadedKey, @(YES), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)imageURL
|
||||||
|
{
|
||||||
|
return objc_getAssociatedObject(self, &imageURLKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sy_cancelCurrentImageLoad
|
||||||
|
{
|
||||||
|
if (self.imageURL)
|
||||||
|
{
|
||||||
|
void *callstack[2];
|
||||||
|
int frames = backtrace(callstack, 2);
|
||||||
|
char **strs = backtrace_symbols(callstack, 2);
|
||||||
|
NSString *func_name = nil;
|
||||||
|
if (frames > 1 && strs && strs[1])
|
||||||
|
{
|
||||||
|
func_name = [NSString stringWithUTF8String:strs[1]];
|
||||||
|
}
|
||||||
|
free(strs);
|
||||||
|
|
||||||
|
//如果从外部调用 cancelImageLoad 才进行扫尾工作
|
||||||
|
if ([func_name rangeOfString:@"UIImageView(WebCache)"].length == 0)
|
||||||
|
{
|
||||||
|
UIButton *pv = [self sy_progressView:NO];
|
||||||
|
// pv.hidden = YES;
|
||||||
|
[pv removeFromSuperview];
|
||||||
|
|
||||||
|
self.status = LKImageViewStatusNone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[self sy_cancelCurrentImageLoad];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadImageURL
|
||||||
|
{
|
||||||
|
id imageURL = self.imageURL;
|
||||||
|
if ([imageURL isKindOfClass:[NSString class]])
|
||||||
|
{
|
||||||
|
if ([imageURL isEqualToString:@""] == NO)
|
||||||
|
{
|
||||||
|
imageURL = [NSURL URLWithString:imageURL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ([imageURL isKindOfClass:[NSURL class]] == NO)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self sy_cancelCurrentImageLoad];
|
||||||
|
|
||||||
|
self.image = nil;
|
||||||
|
self.backgroundColor = [UIColor colorWithRed:233/255.0 green:228/255.0 blue:223/255.0 alpha:1];
|
||||||
|
|
||||||
|
__weak UIImageView *wself = self;
|
||||||
|
if([self originalViewContentMode] < 0){
|
||||||
|
[self setOriginalViewContentMode:self.contentMode];
|
||||||
|
}
|
||||||
|
self.contentMode = UIViewContentModeScaleAspectFill;
|
||||||
|
|
||||||
|
self.status = LKImageViewStatusLoading;
|
||||||
|
|
||||||
|
__weak __block UIButton *pv = [self sy_progressView:YES];
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
pv.hidden = NO;
|
||||||
|
pv.enabled = NO;
|
||||||
|
});
|
||||||
|
|
||||||
|
[self sd_setImageWithURL:imageURL placeholderImage:self.image options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {
|
||||||
|
|
||||||
|
float pvalue = MAX(0, MIN(1, receivedSize / (float) expectedSize));
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
// [pv.titleLabel setText:[NSString stringWithFormat:@"图片加载中%.1f %%",pvalue*100]];
|
||||||
|
[pv setTitle:[NSString stringWithFormat:@"图片加载中%.1f %%",pvalue*100] forState:UIControlStateDisabled];
|
||||||
|
pv.hidden = NO;
|
||||||
|
});
|
||||||
|
|
||||||
|
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
|
||||||
|
if(!pv){
|
||||||
|
pv = [wself sy_progressView:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image)
|
||||||
|
{
|
||||||
|
pv.hidden = YES;
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[pv removeFromSuperview];
|
||||||
|
});
|
||||||
|
|
||||||
|
if([wself originalViewContentMode]>=0){
|
||||||
|
|
||||||
|
if(wself.contentMode != [wself originalViewContentMode]){
|
||||||
|
wself.contentMode = [wself originalViewContentMode];
|
||||||
|
[wself setNeedsDisplay];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (wself.contentMode != UIViewContentModeScaleAspectFill)
|
||||||
|
{
|
||||||
|
wself.contentMode = UIViewContentModeScaleAspectFill;
|
||||||
|
[wself setNeedsDisplay];
|
||||||
|
}
|
||||||
|
|
||||||
|
wself.status = LKImageViewStatusLoaded;
|
||||||
|
wself.backgroundColor = [UIColor clearColor];
|
||||||
|
[wself setOriginalViewContentMode:-1];
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
|
||||||
|
wself.status = LKImageViewStatusFail;
|
||||||
|
[wself setOriginalViewContentMode:-1];
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
pv.enabled = YES;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setOnTouchTapBlock:(void (^)(UIImageView *))onTouchTapBlock
|
||||||
|
{
|
||||||
|
[self sy_loadTapEvent];
|
||||||
|
objc_setAssociatedObject(self, &imageTapEventKey, onTouchTapBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void (^)(UIImageView *))onTouchTapBlock
|
||||||
|
{
|
||||||
|
return objc_getAssociatedObject(self, &imageTapEventKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
|
||||||
|
{
|
||||||
|
if (self.imageURL && self.status != LKImageViewStatusFail && self.onTouchTapBlock == nil)
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if (self.status == LKImageViewStatusLoading || self.status == LKImageViewStatusFail) {
|
||||||
|
UIButton* pv = [self sy_progressView:NO];
|
||||||
|
if (self.status == LKImageViewStatusFail && [pv pointInside:[self convertPoint:point toView:pv] withEvent:event]) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
return [super pointInside:point withEvent:event];
|
||||||
|
}
|
||||||
|
- (void)sy_handleTapEvent:(UITapGestureRecognizer *)sender
|
||||||
|
{
|
||||||
|
switch (self.status)
|
||||||
|
{
|
||||||
|
case LKImageViewStatusFail:
|
||||||
|
[self reloadImageURL];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (self.onTouchTapBlock)
|
||||||
|
{
|
||||||
|
self.onTouchTapBlock(self);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
Reference in New Issue
Block a user