美文网首页
比DZNEmptyDataSet还好用的空数据集界面

比DZNEmptyDataSet还好用的空数据集界面

作者: tt大眼仔 | 来源:发表于2018-04-25 17:53 被阅读44次

DZNEmptyDataSet 是一个嵌入 UITableView/UICollectionView 超类的范畴(category),当视图没有要显示的内容时,它用于显示空数据集界面。

UIScrollView+ACSEmpty 是基本DZNEmptyDataSet原理进行封装的,同样适用于UITableView/UICollectionView / UIScrollView,使用起来也更简单

导入

1.手动导入下面的源代码

2.pod导入

pod 'ACSFramework/EmptyDataset'

使用

     // 导入文件
     #import "UIScrollView+WZQEmpty.h"

    // EmptyFillView为自定义的空视图
    EmptyFillView *emptyView = [[EmptyFillView alloc] initWithFrame:self.baseTableView.bounds];
    emptyView.titleLabel.text = @"没有内容";
    [emptyView.button setTitle:@"去看看其他" forState:UIControlStateNormal];
    [emptyView.button addTarget:self action:@selector(popToBack) forControlEvents:UIControlEventTouchUpInside];
// self.baseTableView 为UITableView
    self.baseTableView.emptyView = emptyView;

源代码

UIScrollView+ACSEmpty.h

#import <UIKit/UIKit.h>

@interface UIScrollView (ACSEmpty)

/** 空视图(tableview,colloctionview 为空时,显示此视图) */
@property (nonatomic, strong) UIView *acs_emptyView;

@end

UIScrollView+ACSEmpty.m

#import "UIScrollView+ACSEmpty.h"
#import <objc/runtime.h>

static char const * const kAcs_EmptyDataSetView =       "acs_emptyDataSetView";

@implementation UIScrollView (ACSEmpty)

- (void)acs_reload {
    if (![self acs_canDisplay]) {
        return;
    }
    if (!self.acs_emptyView) {
        return;
    }
    
    if ([self acs_itemsCount] == 0) {
        if (!self.acs_emptyView.superview) {
            if (([self isKindOfClass:[UITableView class]] || [self isKindOfClass:[UICollectionView class]]) && self.subviews.count > 1) {
                [self insertSubview:self.acs_emptyView atIndex:0];
            }
            else {
                [self addSubview:self.acs_emptyView];
            }
        }
    }else {
        [self.acs_emptyView removeFromSuperview];
    }
}
- (BOOL)acs_canDisplay {
    if ([self isKindOfClass:[UITableView class]] || [self isKindOfClass:[UICollectionView class]] || [self isKindOfClass:[UIScrollView class]]) {
        if (self.acs_emptyView) {
            return YES;
        }
    }
    return NO;
}

- (NSInteger)acs_itemsCount {
    NSInteger items = 0;
    
    // UIScollView doesn't respond to 'dataSource' so let's exit
    if (![self respondsToSelector:@selector(dataSource)]) {
        return items;
    }
    
    // UITableView support
    if ([self isKindOfClass:[UITableView class]]) {
        
        UITableView *tableView = (UITableView *)self;
        id <UITableViewDataSource> dataSource = tableView.dataSource;
        
        NSInteger sections = 1;
        
        if (dataSource && [dataSource respondsToSelector:@selector(numberOfSectionsInTableView:)]) {
            sections = [dataSource numberOfSectionsInTableView:tableView];
        }
        
        if (dataSource && [dataSource respondsToSelector:@selector(tableView:numberOfRowsInSection:)]) {
            for (NSInteger section = 0; section < sections; section++) {
                items += [dataSource tableView:tableView numberOfRowsInSection:section];
            }
        }
    }
    // UICollectionView support
    else if ([self isKindOfClass:[UICollectionView class]]) {
        
        UICollectionView *collectionView = (UICollectionView *)self;
        id <UICollectionViewDataSource> dataSource = collectionView.dataSource;
        
        NSInteger sections = 1;
        
        if (dataSource && [dataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)]) {
            sections = [dataSource numberOfSectionsInCollectionView:collectionView];
        }
        
        if (dataSource && [dataSource respondsToSelector:@selector(collectionView:numberOfItemsInSection:)]) {
            for (NSInteger section = 0; section < sections; section++) {
                items += [dataSource collectionView:collectionView numberOfItemsInSection:section];
            }
        }
    }
    
    return items;
}
#pragma mark - Getters &Setter (Public)
- (UIView *)acs_emptyView {
    UIView *view = objc_getAssociatedObject(self, kAcs_EmptyDataSetView);
    return view;
}
- (void)setAcs_emptyView:(UIView *)emptyView {
    objc_setAssociatedObject(self, kAcs_EmptyDataSetView,emptyView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [self swizzleIfPossible:@selector(reloadData)];
}



#pragma mark - Method Swizzling

static NSMutableDictionary *_impLookupTable;
static NSString *const DZNSwizzleInfoPointerKey = @"pointer";
static NSString *const DZNSwizzleInfoOwnerKey = @"owner";
static NSString *const DZNSwizzleInfoSelectorKey = @"selector";

// Based on Bryce Buchanan's swizzling technique http://blog.newrelic.com/2014/04/16/right-way-to-swizzle/
// And Juzzin's ideas https://github.com/juzzin/JUSEmptyViewController

void dzn_original_implementation(id self, SEL _cmd)
{
    // Fetch original implementation from lookup table
    Class baseClass = acs_baseClassToSwizzleForTarget(self);
    NSString *key = acs_implementationKey(baseClass, _cmd);
    
    NSDictionary *swizzleInfo = [_impLookupTable objectForKey:key];
    NSValue *impValue = [swizzleInfo valueForKey:DZNSwizzleInfoPointerKey];
    
    IMP impPointer = [impValue pointerValue];
    
    // We then inject the additional implementation for reloading the empty dataset
    // Doing it before calling the original implementation does update the 'isEmptyDataSetVisible' flag on time.
    [self acs_reload];
    
    // If found, call original implementation
    if (impPointer) {
        ((void(*)(id,SEL))impPointer)(self,_cmd);
    }
}

NSString *acs_implementationKey(Class class, SEL selector)
{
    if (!class || !selector) {
        return nil;
    }
    
    NSString *className = NSStringFromClass([class class]);
    
    NSString *selectorName = NSStringFromSelector(selector);
    return [NSString stringWithFormat:@"%@_%@",className,selectorName];
}

Class acs_baseClassToSwizzleForTarget(id target)
{
    if ([target isKindOfClass:[UITableView class]]) {
        return [UITableView class];
    }
    else if ([target isKindOfClass:[UICollectionView class]]) {
        return [UICollectionView class];
    }
    else if ([target isKindOfClass:[UIScrollView class]]) {
        return [UIScrollView class];
    }
    
    return nil;
}

- (void)swizzleIfPossible:(SEL)selector
{
    // Check if the target responds to selector
    if (![self respondsToSelector:selector]) {
        return;
    }
    
    // Create the lookup table
    if (!_impLookupTable) {
        _impLookupTable = [[NSMutableDictionary alloc] initWithCapacity:3]; // 3 represent the supported base classes
    }
    
    // We make sure that setImplementation is called once per class kind, UITableView or UICollectionView.
    for (NSDictionary *info in [_impLookupTable allValues]) {
        Class class = [info objectForKey:DZNSwizzleInfoOwnerKey];
        NSString *selectorName = [info objectForKey:DZNSwizzleInfoSelectorKey];
        
        if ([selectorName isEqualToString:NSStringFromSelector(selector)]) {
            if ([self isKindOfClass:class]) {
                return;
            }
        }
    }
    
    Class baseClass = acs_baseClassToSwizzleForTarget(self);
    NSString *key = acs_implementationKey(baseClass, selector);
    NSValue *impValue = [[_impLookupTable objectForKey:key] valueForKey:DZNSwizzleInfoPointerKey];
    
    // If the implementation for this class already exist, skip!!
    if (impValue || !key || !baseClass) {
        return;
    }
    
    // Swizzle by injecting additional implementation
    Method method = class_getInstanceMethod(baseClass, selector);
    IMP dzn_newImplementation = method_setImplementation(method, (IMP)dzn_original_implementation);
    
    // Store the new implementation in the lookup table
    NSDictionary *swizzledInfo = @{DZNSwizzleInfoOwnerKey: baseClass,
                                   DZNSwizzleInfoSelectorKey: NSStringFromSelector(selector),
                                   DZNSwizzleInfoPointerKey: [NSValue valueWithPointer:dzn_newImplementation]};
    
    [_impLookupTable setObject:swizzledInfo forKey:key];
}


@end

相关文章

网友评论

      本文标题:比DZNEmptyDataSet还好用的空数据集界面

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