美文网首页iOS开发指南iOS学习笔记IOS开发者心得
iOS开发 | UITableView的无数据占位图在项目中的实

iOS开发 | UITableView的无数据占位图在项目中的实

作者: 无夜之星辰 | 来源:发表于2017-04-26 20:31 被阅读5437次
少女时代-林允儿

什么是无数据占位图?

无数据占位图,就是当后台返回的数据源为空时需要展示的页面,比如下面这三张:


无数据占位图

为什么我们需要无数据占位图?

一般来说,tableView获取到的数据源为空时,直接展示一个空的tableView显得比较突兀,所以设计师往往会针对这种情况给出相应的UI,用来替代空tableView的展示。

思路:

无数据占位图是一个view,一个覆盖在tableView上的自定义view,这个view可以响应单击手势。

实现方法

要实现这个功能,比较简单,但是,我们的目标是:没有蛀牙(没有蛀牙的意思就是不仅完美实现功能,并且使用非常方便,而且易于修改和维护🙄)。

  • 第一步:封装无数据占位图

这是一个自定义view,根据设计图搭建UI即可,需要注意的是:在一个项目中,无数据占位图往往不止一种(无订单、无收藏的商品、无收获地址。。。),但是它们的布局往往很相似,所以可以通过传入不同的值创建不同的UI。

自定义无数据占位图NoContentView

.h文件:

#import <UIKit/UIKit.h>

// 无数据占位图的类型
typedef NS_ENUM(NSInteger, NoContentType) {
    /** 无网络 */
    NoContentTypeNetwork = 0,
    /** 无订单 */
    NoContentTypeOrder   = 1
};


@interface NoContentView : UIView

/** 无数据占位图的类型 */
@property (nonatomic,assign) NSInteger type;

@end

.m文件

#import "NoContentView.h"
#import "UIColor+Util.h"
#import "Masonry.h"

@interface NoContentView ()<UIScrollViewDelegate>

@property (nonatomic,strong) UIImageView *imageView;
@property (nonatomic,strong) UILabel *topLabel;
@property (nonatomic,strong) UILabel *bottomLabel;

@end

@implementation NoContentView

#pragma mark - 构造方法

- (instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
        // UI搭建
        [self setUpUI];
    }
    return self;
}

#pragma mark - UI搭建
/** UI搭建 */
- (void)setUpUI{
    self.backgroundColor = [UIColor whiteColor];
    
    //------- 图片 -------//
    self.imageView = [[UIImageView alloc]init];
    [self addSubview:self.imageView];
    
    //------- 内容描述 -------//
    self.topLabel = [[UILabel alloc]init];
    [self addSubview:self.topLabel];
    self.topLabel.textAlignment = NSTextAlignmentCenter;
    self.topLabel.font = [UIFont systemFontOfSize:15];
    self.topLabel.textColor = [UIColor colorWithHexString:@"484848"];
    
    //------- 提示点击重新加载 -------//
    self.bottomLabel = [[UILabel alloc]init];
    [self addSubview:self.bottomLabel];
    self.bottomLabel.textAlignment = NSTextAlignmentCenter;
    self.bottomLabel.font = [UIFont systemFontOfSize:15];
    self.bottomLabel.textColor = [UIColor colorWithHexString:@"484848"];
    
    //------- 建立约束 -------//
    [self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerX.mas_equalTo(self);
        make.centerY.mas_offset(-100);
        make.size.mas_equalTo(CGSizeMake(100, 100));
    }];
    
    [self.topLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.imageView.mas_bottom).mas_offset(10);
        make.left.right.mas_offset(0);
        make.height.mas_equalTo(20);
    }];
    
    [self.bottomLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.topLabel.mas_bottom).mas_offset(5);
        make.left.right.mas_offset(0);
        make.height.mas_equalTo(20);
    }];
    
}

#pragma mark - 根据传入的值创建相应的UI
/** 根据传入的值创建相应的UI */
- (void)setType:(NSInteger)type{
    switch (type) {
            
        case NoContentTypeNetwork: // 没网
        {
            [self setImage:@"网络异常" topLabelText:@"貌似没有网络" bottomLabelText:@"点击重试"];
        }
            break;
            
        case NoContentTypeOrder:
        {
            [self setImage:@"订单无数据" topLabelText:@"暂时没有订单" bottomLabelText:@"重新�加载"];
        }
            break;
            
        default:
            break;
    }
}

#pragma mark - 设置图片和文字
/** 设置图片和文字 */
- (void)setImage:(NSString *)imageName topLabelText:(NSString *)topLabelText bottomLabelText:(NSString *)bottomLabelText{
    self.imageView.image = [UIImage imageNamed:imageName];
    self.topLabel.text = topLabelText;
    self.bottomLabel.text = bottomLabelText;
}
  • 第二步:封装BaseTableView

BaseTableView作为基类,需要时可以根据实际情况展示不同样式的无数据占位图,也可以随时将无数据占位图移除。当然,点击这个占位图也会回调相应方法。

.h文件

#import <UIKit/UIKit.h>

@interface BaseTableView : UITableView

// 无数据占位图点击的回调函数
@property (copy,nonatomic) void(^noContentViewTapedBlock)();

/**
 展示无数据占位图

 @param emptyViewType 无数据占位图的类型
 */
- (void)showEmptyViewWithType:(NSInteger)emptyViewType;

/* 移除无数据占位图 */
- (void)removeEmptyView;

@end

.m文件

#import "BaseTableView.h"
#import "NoContentView.h"

@interface BaseTableView (){
    NoContentView *_noContentView;
}

@end

@implementation BaseTableView

/**
 展示无数据占位图
 
 @param emptyViewType 无数据占位图的类型
 */
- (void)showEmptyViewWithType:(NSInteger)emptyViewType{
    
    // 如果已经展示无数据占位图,先移除
    if (_noContentView) {
        [_noContentView removeFromSuperview];
        _noContentView = nil;
    }
    
    //------- 再创建 -------//
    _noContentView = [[NoContentView alloc]initWithFrame:self.bounds];
    [self addSubview:_noContentView];
    _noContentView.type = emptyViewType;
    
    //------- 添加单击手势 -------//
    [_noContentView addGestureRecognizer:[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(noContentViewDidTaped:)]];
}

/* 移除无数据占位图 */
- (void)removeEmptyView{
    [_noContentView removeFromSuperview];
    _noContentView = nil;
}

// 无数据占位图点击
- (void)noContentViewDidTaped:(NoContentView *)noContentView{
    if (self.noContentViewTapedBlock)
    {
        self.noContentViewTapedBlock(); // 调用回调函数
    }
}

@end
  • 使用:

tableView的数据源数组为空时展示,不为空时移除。

    // 展示无数据占位图
    [self.tableView showEmptyViewWithType:NoContentTypeNetwork];
    // 无数据占位图点击的回调
    self.tableView.noContentViewTapedBlock = ^{
        [SVProgressHUD showSuccessWithStatus:@"没网"];
    };

    // 移除无数据占位图
    [self.tableView removeEmptyView];

细节:

  • 根据苹果官方文档的推荐,你的方法名必须直观。
  • 合理使用枚举,看起舒心、写起放心。
  • 为什么是移除无数据占位图而不是隐藏?因为你已经不需要它了,所以也不需要它隐藏。不需要时移除,需要时再建,不要说什么再建消耗内存,你一直隐藏在那里不占内存?这种情况下,随时移除释放资源才是最好的做法。
  • delegate和block的取舍:当两种方式都可以实现相同功能,并且代码可读性不相上下时,采用最终使用时能让使用者敲更少代码的那种方式(我这里用block,使用时就只敲一句代码,如果用delegate,可读性不见得更高,还要多敲两行代码,所以用block)。

demo

你跑不掉的.gif
此文章对应的demo
这个demo更加通用和强大
注:看demo直接从ViewController.m看起

2017年9月26日更新

后面我发现这个轮子不是很优雅,然后重新设计了一个:
iOS开发造轮子 | UIView及其子类的占位图

相关文章

网友评论

本文标题:iOS开发 | UITableView的无数据占位图在项目中的实

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