具体看代码: runtime实现
只需一句代码搞定占位图, (占位图的显示需要调用 reloadData方法)
self.tableView.setEmptyWith(UIImage.init(named: "nodata"), title: "暂无数据", offSet: 0) {[unowned self] in
self.tableView.mj_header?.beginRefreshing()
}
创建scrollview 的category类如下图所示
UIScrollView+Empty.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
/*
1、使用时只需调用此方法,即可在调用SEL: reloadData 时自动判断是否展示空值界面
2、更多定制可根据此实现方案进行相对应拓展 一般会对emptyView 进行定制操作
exp:
[_tableView setEmptyViewWithImage:[UIImage imageNamed:@"noresult"] title:@"某有数据啊,点击我再刷新一次看看?" eventBlock:^{
NSLog(@"点击了,去刷新喽");
}];
*/
/**
空值界面类型
- EmptyImage: 只显示图片
- EmptyTitle: 只显示文字
- EmptyImageAndTitle: 显示图片和文字
*/
typedef NS_ENUM(NSInteger,EmptyType) {
EmptyImage,
EmptyTitle,
EmptyImageAndTitle
};
/**
点击事件回调
*/
typedef void(^EmptyEventBlock)(void);
@interface UIScrollView (Empty)
@property (nonatomic,strong)UIView *emptyView;
@property (nonatomic,copy)EmptyEventBlock emptyEventBlock;
/**
设置空值界面
根据传入内容决定展示风格: 图片、文字、文字和图片、是否添加点击事件
@param image 展示图片 可为空
@param title 展示文字 可为空
@param block 点击事件block 可为空 为空则没有点击事件
*/
- (void)setEmptyViewWithImage:(UIImage *_Nullable)image title:(NSString *_Nullable)title offSet:(CGFloat)offSet eventBlock:(EmptyEventBlock _Nullable)block;
@end
@interface UITableView (Empty)
@end
@interface UICollectionView (Empty)
@end
NS_ASSUME_NONNULL_END
UIScrollView+Empty.m
#import "UIScrollView+Empty.h"
#import <objc/runtime.h>
#define BaseNavBarHeight ([[UIApplication sharedApplication] statusBarFrame].size.height+44)
#define rgba(r,g,b,a) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]
static NSString *kEmptyViewKey = @"EmptyViewKey";
static NSString *kEmptyEventBlockKey = @"EmptyEventBlockKey";
@implementation UIScrollView (Empty)
- (void)setEmptyView:(UIView *)emptyView {
objc_setAssociatedObject(self, &kEmptyViewKey, emptyView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIView *)emptyView {
return objc_getAssociatedObject(self, &kEmptyViewKey);
}
- (void)setEmptyEventBlock:(EmptyEventBlock)emptyEventBlock {
objc_setAssociatedObject(self, &kEmptyEventBlockKey, emptyEventBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (EmptyEventBlock)emptyEventBlock {
return objc_getAssociatedObject(self, &kEmptyEventBlockKey);
}
- (void)setEmptyViewWithImage:(UIImage *_Nullable)image title:(NSString *_Nullable)title offSet:(CGFloat)offSet eventBlock:(EmptyEventBlock _Nullable)block {
if (!self.emptyView) {
EmptyType type;
if (image && !title) {
type = EmptyImage;
}else if (!image && title) {
type = EmptyTitle;
}else if (image && title) {
type = EmptyImageAndTitle;
}else{
NSLog(@"参数错误,不能使用此功能");
return;
}
UIButton *emptyBtn = [UIButton buttonWithType:UIButtonTypeCustom];
block ? (emptyBtn.enabled = YES) : (emptyBtn.enabled = NO);
(emptyBtn.enabled = YES) ? [emptyBtn addTarget:self action:@selector(emptyClick:) forControlEvents:UIControlEventTouchUpInside]:nil;
(emptyBtn.enabled = YES) ? (self.emptyEventBlock = block) : nil;
CGFloat ksScreenWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat ksScreenHeight = [UIScreen mainScreen].bounds.size.height;
switch (type) {
case EmptyImage:
{
emptyBtn.frame = CGRectMake((ksScreenWidth-image.size.width)/2, (ksScreenHeight - image.size.height)/2 - BaseNavBarHeight + offSet, image.size.width, image.size.height);
[emptyBtn setImage:image forState:UIControlStateNormal];
}
break;
case EmptyTitle:
{
CGRect titleRect = [title boundingRectWithSize:CGSizeMake(ksScreenWidth, 20) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIFont systemFontOfSize:16.0f],NSFontAttributeName, nil] context:nil];
emptyBtn.frame = CGRectMake((ksScreenWidth-titleRect.size.width)/2, (ksScreenHeight-titleRect.size.height)/2 + offSet, titleRect.size.width, titleRect.size.height);
[emptyBtn setTitle:title forState:UIControlStateNormal];
[emptyBtn setTitleColor:rgba(143, 143, 143, 1) forState:UIControlStateNormal];
}
break;
case EmptyImageAndTitle:
{
CGFloat btnWidth = 0;
CGFloat btnHeight = 0;
UIFont *titleFont = [UIFont systemFontOfSize:16.0f];
CGRect titleRect = [title boundingRectWithSize:CGSizeMake(ksScreenWidth, 20) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:[NSDictionary dictionaryWithObjectsAndKeys:titleFont,NSFontAttributeName, nil] context:nil];
titleRect.size.width <= image.size.width ? (btnWidth = image.size.width) : (btnWidth = titleRect.size.width);
btnHeight = image.size.height + titleRect.size.height + 10;
emptyBtn.frame = CGRectMake((ksScreenWidth-btnWidth)/2, (ksScreenHeight-btnHeight)/2 - BaseNavBarHeight + offSet, btnWidth, btnHeight);
[emptyBtn setImage:image forState:UIControlStateNormal];
[emptyBtn setTitle:title forState:UIControlStateNormal];
[emptyBtn setTitleColor:rgba(143, 143, 143, 1) forState:UIControlStateNormal];
[emptyBtn setImageEdgeInsets:UIEdgeInsetsMake(0, 0, 30, -titleRect.size.width)];
[emptyBtn setTitleEdgeInsets:UIEdgeInsetsMake(btnHeight-20, -image.size.width, 0, 0)];
emptyBtn.titleLabel.font = titleFont;
}
break;
default:
break;
}
self.emptyView = emptyBtn;
self.emptyView.hidden = YES;
[self addSubview:self.emptyView];
}
[self bringSubviewToFront:self.emptyView];
}
/// 更新界面,是否展示空值视图
- (void)refreshEmptyView {
NSInteger section = 1;
NSInteger rows = 0;
if ([self isKindOfClass:[UITableView class]]) {
UITableView *tableView = (UITableView *)self;
if (tableView.dataSource != nil && [tableView.dataSource respondsToSelector:@selector(tableView:numberOfRowsInSection:)]) {
if ([tableView.dataSource respondsToSelector:@selector(numberOfSectionsInTableView:)]) {
section = [tableView.dataSource numberOfSectionsInTableView:tableView];
}
for (int i = 0; i < section; i++) {
rows += [tableView.dataSource tableView:tableView numberOfRowsInSection:i];
}
}
}else if ([self isKindOfClass:[UICollectionView class]]) {
UICollectionView *collectionView = (UICollectionView *)self;
if (collectionView.dataSource != nil && [collectionView.dataSource respondsToSelector:@selector(collectionView:numberOfItemsInSection:)]) {
if ([collectionView.dataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)]) {
section = [collectionView.dataSource numberOfSectionsInCollectionView:collectionView];
}
for (int i = 0; i < section; i++) {
rows += [collectionView.dataSource collectionView:collectionView numberOfItemsInSection:i];
}
}
}
if (rows == 0) {
self.emptyView.hidden = NO;
[self bringSubviewToFront:self.emptyView];
}else{
self.emptyView.hidden = YES;
return;
}
}
#pragma mark -- action
- (void)emptyClick:(UIButton *)sender {
if (self.emptyEventBlock) {
self.emptyEventBlock();
}
}
#pragma mark -- swizzing
+ (void)hookClass:(Class)classObject originalSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
Class class = classObject;
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
if (didAddMethod) {
originalMethod = class_getInstanceMethod(class, originalSelector);
}
method_exchangeImplementations(swizzledMethod, originalMethod);
}
@end
@implementation UITableView (Empty)
// 加载完数据的标记属性名
static NSString *const kRLTableViewPropertyInitFinish = @"kRLTableViewPropertyInitFinish";
/**
设置已经加载完成的数据
*/
- (void)setIsInitFinish:(BOOL)finish{
objc_setAssociatedObject(self, &kRLTableViewPropertyInitFinish, @(finish), OBJC_ASSOCIATION_ASSIGN);
}
/**
是否已经加载完成数据
*/
- (BOOL)isInitFinish{
id obj = objc_getAssociatedObject(self, &kRLTableViewPropertyInitFinish);
return [obj boolValue];
}
+ (void)load {
[super load];
[self hookClass:[self class] originalSelector:@selector(reloadData) swizzledSelector:@selector(customReloadData)];
}
- (void)customReloadData {
[self customReloadData];
//忽略第一次加载
if (![self isInitFinish]) {
[self setIsInitFinish:YES];
return;
}
[self refreshEmptyView];
}
@end
@implementation UICollectionView (Empty)
// 加载完数据的标记属性名
static NSString *const kRLCollectionViewPropertyInitFinish = @"kRLCollectionViewPropertyInitFinish";
/**
设置已经加载完成的数据
*/
- (void)setIsInitFinish:(BOOL)finish{
objc_setAssociatedObject(self, &kRLCollectionViewPropertyInitFinish, @(finish), OBJC_ASSOCIATION_ASSIGN);
}
/**
是否已经加载完成数据
*/
- (BOOL)isInitFinish{
id obj = objc_getAssociatedObject(self, &kRLCollectionViewPropertyInitFinish);
return [obj boolValue];
}
+ (void)load {
[super load];
[self hookClass:[self class] originalSelector:@selector(reloadData) swizzledSelector:@selector(customReloadData)];
}
- (void)customReloadData {
[self customReloadData];
//忽略第一次加载
if (![self isInitFinish]) {
return;
}
[self refreshEmptyView];
}
@end
网友评论