app 顯示列表內(nèi)容時(shí), 在某一時(shí)刻可能數(shù)據(jù)為空(等待網(wǎng)絡(luò)請求/網(wǎng)絡(luò)請求失敗)等, 添加一個(gè)空白指示頁將有效緩解用戶可能造成的焦慮或混亂. 并可以幫助用戶處理問題.
市面上已經(jīng)有部分成熟的空白頁框架,最典型的就是使用DZNEmptyDataSet.
但是其使用
DZNEmptyDataSetDelegate
,DZNEmptyDataSetSource
來定制空白頁元素,使用時(shí)較為繁瑣.筆者借鑒其原理的基礎(chǔ)上,制作了對標(biāo)框架(單向?qū)?biāo))EmptyPage來簡化日常項(xiàng)目開發(fā).
前言
EmptyPage 歷時(shí)1年, 在我司項(xiàng)目中穩(wěn)定使用迭代6個(gè)版本,算是比較穩(wěn)定.
支持UICollectionView & UITableView.
ps: 目前階段只提供 swift 版本.
image
|
image
|
---|---|
實(shí)現(xiàn)原理
該核心部分 作為一個(gè)單獨(dú)的子庫 實(shí)現(xiàn), 可使用 以下方式單獨(dú)引用.
pod 'EmptyPage/Core'
具體代碼可查閱 Github Link, 超級簡單.
-
為
UIScrollView
添加emptyView
對象作為空白頁實(shí)例:public extension UIScrollView { public var emptyView: UIView? }
-
Method Swizzling
方式替換掉UITableView
\UICollectionView
中部分相關(guān)函數(shù).以下拿UITableView
舉例:// DZNEmptyDataSet 對 autolayout 項(xiàng)目不太友好. (也可能本人沒深度使用...) // EmptyPage // UITableView frame 變化相關(guān)函數(shù) open func layoutSubviews() open func layoutIfNeeded() // 數(shù)據(jù)源增減相關(guān)函數(shù) open func insertRows(at indexPaths: [IndexPath], with animation: UITableView.RowAnimation) open func deleteRows(at indexPaths: [IndexPath], with animation: UITableView.RowAnimation) open func insertSections(_ sections: IndexSet, with animation: UITableView.RowAnimation) open func deleteSections(_ sections: IndexSet, with animation: UITableView.RowAnimation) open func reloadData()
-
在數(shù)據(jù)/frame變化時(shí)判斷空白頁顯示與隱藏.
func setEmptyView(event: () -> ()) { oldEmptyView?.removeFromSuperview() event() guard bounds.width != 0, bounds.height != 0 else { return } var isHasRows = false let sectionCount = dataSource?.numberOfSections?(in: self) ?? numberOfSections for index in 0..<sectionCount { if numberOfRows(inSection: index) > 0 { isHasRows = true break } } isScrollEnabled = isHasRows if isHasRows { emptyView?.removeFromSuperview() return } guard let view = emptyView else{ return } view.frame = bounds addSubview(view) sendSubview(toBack: view) }
-
使用
UITableView().emptyView = CustomView() UICollectionView().emptyView = CustomView()
UITableView().emptyView 第一次被賦值時(shí)才會進(jìn)行
Method Swizzling
相關(guān)函數(shù).
模板視圖
DZNEmptyDataSet 的成功離不開其可高度定制化的模板視圖.但其繁瑣的 delegate apis 遠(yuǎn)不如自定義視圖來的方便, 其對自定義視圖的支持也并不友善.
EmptyPage 優(yōu)先支持 自定義視圖,并附贈 3 套可以湊合看的模板視圖(支持超級高自定義調(diào)節(jié),但畢竟UI我們說了不算...)
采用 以下方式 則包含該部分內(nèi)容:
pod 'EmptyPage'
-
自定義視圖
-
僅支持autolayout布局模式
不使用 autolayout 模式:
pod 'EmptyPage/Core'
UITableView().emptyView = CustomView()
-
自定義視圖需要autolayout實(shí)現(xiàn)自適應(yīng)高
可以參考 內(nèi)置的幾套模板視圖的約束實(shí)現(xiàn).
-
添加 EmptyPageContentViewProtocol 協(xié)議
該協(xié)議默認(rèn)實(shí)現(xiàn)了將自定義視圖居中約束至一個(gè)
backgroundView
上.通用性考慮: backgroundView.frame 與 tableView.frame 相同
示例:
class CustomView: EmptyPageContentViewProtocol{ ... } let customView = CustomView() UITableView().emptyView = customView.mix()
不添加該協(xié)議,可采用以下方式:
UITableView().emptyView = EmptyPageView.mix(view: customView)
-
視圖關(guān)系
視圖關(guān)系
-
-
內(nèi)置模板視圖
**特性: **
- 支持鏈?zhǔn)秸{(diào)用.
- 元素支持高度自定義.
- 同樣依照自定義視圖的標(biāo)準(zhǔn)實(shí)現(xiàn).
ps: 完全等同于提前寫好的自定義模板視圖.
-
目前可以選擇3套基本的模板視圖.
文字模板(
EmptyPageView.ContentView.onlyText
)圖片模板(
EmptyPageView.ContentView.onlyImage
)混合模板(
EmptyPageView.ContentView.standard
)
文字模板圖片模板混合模板
-
使用
-
示例:
UITableView().emptyView = EmptyPageView.ContentView.standard .change(hspace: .button, value: 80) .change(height: .button, value: 60) .change(hspace: .image, value: 15) .config(button: { (item) in item.backgroundColor = UIColor.blue item.contentEdgeInsets = UIEdgeInsets(top: 8, left: 20, bottom: 8, right: 20) }) .set(image: UIImage(named: "empty-1002")!) .set(title: "Connection failure", color: UIColor.black, font: UIFont.boldSystemFont(ofSize: 24)) .set(text: "Something has gone wrong with the internet connection. Let's give it another shot.", color: UIColor.black, font: UIFont.systemFont(ofSize: 15)) .set(buttonTitle: "TRY AGAIN") .set(tap: { // 點(diǎn)擊事件 }) .mix()
-
-
Apis
模板視圖中總結(jié)起來只有三種配置函數(shù):
-
約束配置函數(shù):
func change(...) -> Self
約束函數(shù)具體可配置項(xiàng)采用枚舉的形式限定.(以免改變/沖突自適應(yīng)高度相關(guān)約束)
enum HSpaceType { } // 修改視圖水平方向上的間距
enum VSpaceType { } // 修改視圖垂直方向上的間距
enum HeightType { } // 修改視圖具體高度
例如:
standardView.change(hspace: .button, value: 80) .change(height: .button, value: 60)
-
控件配置函數(shù):
func set(...) -> Self
提供了簡單的文本/字體/圖片/顏色配置.例如:
standardView.set(title: "Connection failure", color: UIColor.black, font: UIFont.boldSystemFont(ofSize: 24))
-
控件自定義配置函數(shù):
func config(element: { (element) in ... }) -> Self
返回一個(gè)完整的控件,可供深度配置. 例如:
standardView.config(button: { (item) in item.backgroundColor = UIColor.blue item.contentEdgeInsets = UIEdgeInsets(top: 8, left: 20, bottom: 8, right: 20) })
-
視圖混合函數(shù)
func mix()
:該函數(shù)由 EmptyPageContentViewProtocol 協(xié)議默認(rèn)實(shí)現(xiàn).
作用: 將視圖約束至 backgroundView 上
ps: 別忘了...
-
結(jié)尾
項(xiàng)目開源鏈接: Github/EmptyPage
個(gè)人博客鏈接: 四方田