DZEmptyDataSet是用来给TableView的数据源的个数为0的时候设置自定义界面提示的框架,设置和刷新起来都很方便好使.但是为了满足项目的业务逻辑和代码简洁我们仍然需要做一些封装操作.
在项目中有列表TableView的情况下,为了优化用户体验我们通常会做下面的事情..
一 . 在tableView的数据源正在加载的情况下,界面会是一片空白,如果没有设置分割线的style = none 还会存在很多个横线.所以我们需要给用户一个"菊花"加载提示.
二. 在tableView的数据源加载完毕,但是数据为空的情况下,给予用户一个"暂无数据"的界面.
三. 在tableView的数据源加载失败(网络情况很差)的情况下,给用户显示一个"网络连接失败,点击重试"的界面.
这三种界面都会在同一个tableView中遇到,也就是说一个tableView会根据不同的情况展示三种不同的empty界面..而且项目中可能会有多个tableView具有相同的empty配置,每一个控制器中进行一此配置是不合理的.我们抽取一个继承UITableViewController的基类.统一在empty的代理中根据不同情况展示不同界面会方便很多.
定义一个枚举来描述当前datasource为0的情况
enum TableViewDataState {
case loadingData // 正在加载数据中
case emptyData // 加载完毕,数据为空
case abnormal // 网络出现问题
}
声明一个描述当前数据状态的枚举属性,并给tableView设置DZEmpty协议
class DownloadBaseVC: UITableViewController {
var dataState: TableViewDataState = .loadingData
override func viewDidLoad() {
super.viewDidLoad()
tableView.emptyDataSetDelegate = self
tableView.emptyDataSetSource = self
}
}
接下来在代理中根据dataState的状态,展示不同的界面或者"菊花"
extension DownloadBaseVC: DZNEmptyDataSetDelegate, DZNEmptyDataSetSource {
func image(forEmptyDataSet scrollView: UIScrollView!) -> UIImage! {
switch dataState {
case .emptyData:
return UIImage(named: "noData_downloading")!
case .loadingData:
return #imageLiteral(resourceName: "loading.png")
case .abnormal:
return #imageLiteral(resourceName: "loading.png")
}
}
func imageAnimation(forEmptyDataSet scrollView: UIScrollView!) -> CAAnimation! {
let animation = CABasicAnimation(keyPath: "transform.rotation.z")
animation.fromValue = 0
animation.toValue = 2 * Double.pi
animation.duration = 1
animation.repeatCount = MAXFLOAT
return animation
}
func buttonTitle(forEmptyDataSet scrollView: UIScrollView!, for state: UIControlState) -> NSAttributedString! {
switch dataState {
case .emptyData:
return NSAttributedString(string: "去看看", attributes: [NSForegroundColorAttributeName: UIColor.orange, NSFontAttributeName: UIFont.systemFont(ofSize: 14)])
case .loadingData:
return NSAttributedString(string: "")
case .abnormal:
return NSAttributedString(string: "网络出现异常,点击重试")
}
}
func emptyDataSet(_ scrollView: UIScrollView!, didTap button: UIButton!) {
switch dataState {
case .emptyData:
navigationController?.pushViewController(ListenTodayFireVC(), animated: true)
case .loadingData: break
case .abnormal:
print("尝试了重新连接")
}
}
func emptyDataSetShouldAnimateImageView(_ scrollView: UIScrollView!) -> Bool {
return dataState == .loadingData
}
}
如果某一个界面的tableView与基类中的界面配置不同,通过重写某一个协议方法覆盖了就可以.
这种方式一般用于很多列表具有相同业务判断的时候...定制某一个界面的empty我们也可以不使用DZEmpty,自定义一个View(可以传入title和image),根据不同情况控制view的隐藏也是一种实现方式.
注: 有时间要用Swift自己写一个DZEmpty,这个框架的源码很值得学习.
示意图: