美文网首页
比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