開發(fā)場(chǎng)景:
iOS開發(fā)中常見的這么一種情形,UITableView
顯示網(wǎng)絡(luò)請(qǐng)求的數(shù)據(jù)列表,在無網(wǎng)絡(luò)或者服務(wù)器返回內(nèi)容為空時(shí),需要顯示占位view
,以提醒用戶當(dāng)前無數(shù)據(jù).
常規(guī)思路
通常我們是在網(wǎng)絡(luò)請(qǐng)求結(jié)束后,通過判斷返回?cái)?shù)據(jù) dataList.count == 0
,來設(shè)置占位view
來替換或者覆蓋tableView
.這么做需要逐個(gè)列表控制器處理,代碼分散不易集中管理.
我的方案
這里提供一種簡(jiǎn)便快捷的方案.可以滿足一般性的需求.
-
思路
- 通過判斷
UITableViewDataSource
數(shù)據(jù)源方法numberOfSection
和numberOfRowsInSection
來判斷是否有cell要被加載. - 當(dāng)有
cell
時(shí),設(shè)置tableView
的tableFooterView = UIView()
,不顯示footer
;當(dāng)cell
為空時(shí),設(shè)置tableFooterView = CustomPlaceHolderView()
- 通過判斷
-
實(shí)現(xiàn)
- 協(xié)議+擴(kuò)展默認(rèn)實(shí)現(xiàn) 以減少代碼量和代碼耦合
- 用戶主動(dòng)調(diào)度
設(shè)置占位view
函數(shù),靈活簡(jiǎn)便
protocol TableEmptable {
/// 列表是否為空
var isEmptyData: Bool { get }
/// 提供占位view,該view將占據(jù)tableView的tableFooterView
var placeHolderView: UIView { get }
/// 建議在reloadData前,調(diào)用該方法
func setPlaceholderIfNeed()
}
extension TableEmptable where Self : UITableViewController {
var isEmptyData: Bool {
let sectionCount: Int = numberOfSections(in: self.tableView)
if sectionCount == 0 { return true }
for section in 0 ..< sectionCount {
if tableView(tableView, numberOfRowsInSection: section) != 0 { return false }
}
return true
}
var placeHolderView: UIView {
let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: kScreenWidth, height: 375))
imgView.image = UIImage(named: "ooxx")
return imgView
}
func setPlaceholderIfNeed() {
if self.isEmptyData {
self.tableView.tableFooterView = placeHolderView
} else {
self.tableView.tableFooterView = UIView()
}
}
}
如何使用
- 遵守
TableEmptable
協(xié)議(MyTableViewController : TableEmptable
) - 在
reloadData
前調(diào)用setPlaceHolderIfNeed
(當(dāng)然別忘了你的placeHolderView
需要自己定義)
測(cè)試代碼
import UIKit
fileprivate let cellID = "identifier_KHCardController"
class TestController: UITableViewController , TableEmptable {
var list : [String] = Array(repeating: "ooxx", count: Int(arc4random_uniform(2)))
override func viewDidLoad() {
super.viewDidLoad()
title = "測(cè)試"
view.backgroundColor = UIColor.white
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellID)
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.refresh, target: self, action: #selector(reload))
/// 設(shè)置占位圖
setPlaceholderIfNeed()
}
}
extension TestController {
override func numberOfSections(in tableView: UITableView) -> Int {
return 5
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
cell.textLabel?.text = list[indexPath.row] + "\(indexPath)"
return cell
}
}
extension TestController {
@objc fileprivate func reload() {
list = Array(repeating: "ooxx", count: Int(arc4random_uniform(2)))
/// 設(shè)置占位圖
setPlaceholderIfNeed()
self.tableView.reloadData()
}
}