app 顯示列表內(nèi)容時, 在某一時刻可能數(shù)據(jù)為空(等待網(wǎng)絡請求/網(wǎng)絡請求失敗)等, 添加一個空白指示頁將有效緩解用戶可能造成的焦慮或混亂. 并可以幫助用戶處理問題.
市面上已經(jīng)有部分成熟的空白頁框架,最典型的就是使用DZNEmptyDataSet.
但是其使用
DZNEmptyDataSetDelegate,DZNEmptyDataSetSource來定制空白頁元素,使用時較為繁瑣.筆者借鑒其原理的基礎上,制作了對標框架(單向?qū)?EmptyPage來簡化日常項目開發(fā).
前言
EmptyPage 歷時1年, 在我司項目中穩(wěn)定使用迭代6個版本,算是比較穩(wěn)定.
支持UICollectionView & UITableView.
ps: 目前階段只提供 swift 版本.
![]() image
|
![]() image
|
|---|---|
實現(xiàn)原理
該核心部分 作為一個單獨的子庫 實現(xiàn), 可使用 以下方式單獨引用.
pod 'EmptyPage/Core'具體代碼可查閱 Github Link, 超級簡單.
-
為
UIScrollView添加emptyView對象作為空白頁實例:public extension UIScrollView { public var emptyView: UIView? } -
Method Swizzling方式替換掉UITableView\UICollectionView中部分相關函數(shù).以下拿UITableView舉例:// DZNEmptyDataSet 對 autolayout 項目不太友好. (也可能本人沒深度使用...) // EmptyPage // UITableView frame 變化相關函數(shù) open func layoutSubviews() open func layoutIfNeeded() // 數(shù)據(jù)源增減相關函數(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變化時判斷空白頁顯示與隱藏.
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 第一次被賦值時才會進行
Method Swizzling相關函數(shù).
模板視圖
DZNEmptyDataSet 的成功離不開其可高度定制化的模板視圖.但其繁瑣的 delegate apis 遠不如自定義視圖來的方便, 其對自定義視圖的支持也并不友善.
EmptyPage 優(yōu)先支持 自定義視圖,并附贈 3 套可以湊合看的模板視圖(支持超級高自定義調(diào)節(jié),但畢竟UI我們說了不算...)
采用 以下方式 則包含該部分內(nèi)容:
pod 'EmptyPage'
-
自定義視圖
-
僅支持autolayout布局模式
不使用 autolayout 模式:
pod 'EmptyPage/Core'UITableView().emptyView = CustomView()
-
自定義視圖需要autolayout實現(xiàn)自適應高
可以參考 內(nèi)置的幾套模板視圖的約束實現(xiàn).
-
添加 EmptyPageContentViewProtocol 協(xié)議
該協(xié)議默認實現(xiàn)了將自定義視圖居中約束至一個
backgroundView上.通用性考慮: backgroundView.frame 與 tableView.frame 相同
示例:
class CustomView: EmptyPageContentViewProtocol{ ... } let customView = CustomView() UITableView().emptyView = customView.mix()不添加該協(xié)議,可采用以下方式:
UITableView().emptyView = EmptyPageView.mix(view: customView)
-
視圖關系
視圖關系
-
-
內(nèi)置模板視圖
**特性: **
- 支持鏈式調(diào)用.
- 元素支持高度自定義.
- 同樣依照自定義視圖的標準實現(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: { // 點擊事件 }) .mix()
-
-
Apis
模板視圖中總結起來只有三種配置函數(shù):
-
約束配置函數(shù):
func change(...) -> Self約束函數(shù)具體可配置項采用枚舉的形式限定.(以免改變/沖突自適應高度相關約束)
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返回一個完整的控件,可供深度配置. 例如:
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é)議默認實現(xiàn).
作用: 將視圖約束至 backgroundView 上
ps: 別忘了...
-
結尾
項目開源鏈接: Github/EmptyPage
個人博客鏈接: 四方田





