#import "UICollectionView+NoDataView.h"
#import
#import "NoDataView.h"
/**
消除警告*/
@protocol CollectionViewDelegate @optional- (UIView *)noDataView;- (UIImage *)noDataViewImage;- (NSString *)noDataViewMessage;- (UIColor *)noDataViewMessageColor;- (NSNumber *)noDataViewCenterYOffset;@end
@implementationUICollectionView (NoDataView)/**
加载时, 交换方法*/
+ (void)load {//只交换一次
staticdispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method reloadData=class_getInstanceMethod(self, @selector(reloadData));
Method replace_reloadData=class_getInstanceMethod(self, @selector(replace_reloadData));
method_exchangeImplementations(reloadData, replace_reloadData);
Method dealloc= class_getInstanceMethod(self, NSSelectorFromString(@"dealloc"));
Method replace_dealloc=class_getInstanceMethod(self, @selector(replace_dealloc));
method_exchangeImplementations(dealloc, replace_dealloc);
});
}/**
在 ReloadData 的时候检查数据*/
- (void)replace_reloadData {
[self replace_reloadData];//忽略第一次加载
if (![self isInitFinish]) {
[self havingData:YES];
[self setIsInitFinish:YES];return;
}//刷新完成之后检测数据量
dispatch_async(dispatch_get_main_queue(), ^{
NSInteger numberOfSections=[self numberOfSections];
BOOL havingData=NO;for (NSInteger i = 0; i < numberOfSections; i++) {if ([self numberOfItemsInSection:i] > 0) {
havingData=YES;break;
}
}
[self havingData:havingData];
});
}/**
展示占位图*/
- (void)havingData:(BOOL)havingData {//不需要显示占位图
if(havingData) {
[self freeNoDataViewIfNeeded];
self.backgroundView=nil;return;
}//不需要重复创建
if(self.backgroundView) {return;
}//自定义了占位图
if ([self.delegaterespondsToSelector:@selector(noDataView)]) {
self.backgroundView= [self.delegateperformSelector:@selector(noDataView)];return;
}//使用自带的
UIImage *img =nil;
NSString*msg = @"暂无数据";
UIColor*color =[UIColor lightGrayColor];
CGFloat offset= 0;//获取图片
if ([self.delegaterespondsToSelector:@selector(noDataViewImage)]) {
img= [self.delegateperformSelector:@selector(noDataViewImage)];
}//获取文字
if ([self.delegaterespondsToSelector:@selector(noDataViewMessage)]) {
msg= [self.delegateperformSelector:@selector(noDataViewMessage)];
}//获取颜色
if ([self.delegaterespondsToSelector:@selector(noDataViewMessageColor)]) {
color= [self.delegateperformSelector:@selector(noDataViewMessageColor)];
}//获取偏移量
if ([self.delegaterespondsToSelector:@selector(noDataViewCenterYOffset)]) {
offset= [[self.delegateperformSelector:@selector(noDataViewCenterYOffset)] floatValue];
}//创建占位图
self.backgroundView =[self defaultNoDataViewWithImage :img message:msg color:color offsetY:offset];
}/**
默认的占位图*/
- (UIView *)defaultNoDataViewWithImage:(UIImage *)image message:(NSString *)message color:(UIColor *)color offsetY:(CGFloat)offset {//计算位置, 垂直居中, 图片默认中心偏上.
CGFloat sW =self.bounds.size.width;
CGFloat cX= sW / 2;
CGFloat cY= self.bounds.size.height * (1 - 0.618) +offset;
CGFloat iW=image.size.width;
CGFloat iH=image.size.height;//图片
UIImageView *imgView =[[UIImageView alloc] init];
imgView.frame= CGRectMake(cX - iW / 2, cY - iH / 2, iW, iH);
imgView.image=image;//文字
UILabel *label =[[UILabel alloc] init];
label.font= [UIFont systemFontOfSize:17];
label.textColor=color;
label.text=message;
label.textAlignment=NSTextAlignmentCenter;
label.frame= CGRectMake(0, CGRectGetMaxY(imgView.frame) + 24, sW, label.font.lineHeight);//视图
NoDataView * view =[[NoDataView alloc] init];
[view addSubview:imgView];
[view addSubview:label];//实现跟随 collectionView 滚动
[view addObserver:self forKeyPath:kNoDataViewObserveKeyPath options:NSKeyValueObservingOptionNew context:nil];returnview;
}/**
监听*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {if([keyPath isEqualToString:kNoDataViewObserveKeyPath]) {/**
在 collectionView 滚动 ContentOffset 改变时, 会同步改变 backgroundView 的 frame.origin.y
可以实现, backgroundView 位置相对于 collectionView 不动, 但是我们希望
backgroundView 跟随 collectionView 的滚动而滚动, 只能强制设置 frame.origin.y 永远为 0
兼容 MJRefresh*/CGRect frame=[[change objectForKey:NSKeyValueChangeNewKey] CGRectValue];if (frame.origin.y != 0) {
frame.origin.y= 0;
self.backgroundView.frame=frame;
}
}
}#pragma mark - 属性
///加载完数据的标记属性名
static NSString * const kCollectionViewPropertyInitFinish = @"kCollectionViewPropertyInitFinish";/**
设置已经加载完成数据了*/
- (void)setIsInitFinish:(BOOL)finish {
objc_setAssociatedObject(self,&kCollectionViewPropertyInitFinish, @(finish), OBJC_ASSOCIATION_ASSIGN);
}/**
是否已经加载完成数据*/
-(BOOL)isInitFinish {id obj = objc_getAssociatedObject(self, &kCollectionViewPropertyInitFinish);return[obj boolValue];
}/**
移除 KVO 监听*/
- (void)freeNoDataViewIfNeeded {if ([self.backgroundView isKindOfClass:[NoDataView class]]) {
[self.backgroundView removeObserver:self forKeyPath:kNoDataViewObserveKeyPath context:nil];
}
}- (void)replace_dealloc {
[self freeNoDataViewIfNeeded];
[self replace_dealloc];
NSLog(@"CollectionView 视图正常销毁");
}@end