app 顯示列表內容時, 在某一時刻可能數據爲空(等待網絡請求/網絡請求失敗)等, 添加一個空白指示頁將有效緩解用戶可能形成的焦慮或混亂. 並能夠幫助用戶處理問題.git
市面上已經有部分紅熟的空白頁框架,最典型的就是使用DZNEmptyDataSet.github
可是其使用
DZNEmptyDataSetDelegate
,DZNEmptyDataSetSource
來定製空白頁元素,使用時較爲繁瑣.swift筆者借鑑其原理的基礎上,製做了對標框架(單向對標)EmptyPage來簡化平常項目開發.api
EmptyPage 歷時1年, 在我司項目中穩定使用迭代6個版本,算是比較穩定.ruby
支持UICollectionView & UITableView.網絡
ps: 目前階段只提供 swift 版本.app
![]() |
![]() |
![]() |
---|---|---|
該核心部分 做爲一個單獨的子庫 實現, 可以使用 如下方式單獨引用.框架
pod 'EmptyPage/Core' 複製代碼
具體代碼可查閱 Github Link, 超級簡單.函數
UIScrollView
添加emptyView
對象做爲空白頁實例:public extension UIScrollView {
public var emptyView: UIView?
}
複製代碼
Method Swizzling
方式替換掉UITableView
\ UICollectionView
中部分相關函數.如下拿UITableView
舉例:// DZNEmptyDataSet 對 autolayout 項目不太友好. (也可能本人沒深度使用...)
// EmptyPage
// UITableView frame 變化相關函數
open func layoutSubviews()
open func layoutIfNeeded()
// 數據源增減相關函數
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()
複製代碼
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
相關函數.
DZNEmptyDataSet 的成功離不開其可高度定製化的模板視圖.但其繁瑣的 delegate apis 遠不如自定義視圖來的方便, 其對自定義視圖的支持也並不友善.
EmptyPage 優先支持 自定義視圖,並附贈 3 套能夠湊合看的模板視圖(支持超級高自定義調節,但畢竟UI咱們說了不算...)
採用 如下方式 則包含該部份內容:
pod 'EmptyPage' 複製代碼
僅支持autolayout佈局模式
不使用 autolayout 模式:
pod 'EmptyPage/Core'
UITableView().emptyView = CustomView()
自定義視圖須要autolayout實現自適應高
能夠參考 內置的幾套模板視圖的約束實現.
添加 EmptyPageContentViewProtocol 協議
該協議默認實現了將自定義視圖居中約束至一個backgroundView
上.
通用性考慮: backgroundView.frame 與 tableView.frame 相同
示例:
class CustomView: EmptyPageContentViewProtocol{
...
}
let customView = CustomView()
UITableView().emptyView = customView.mix()
複製代碼
不添加該協議,可採用如下方式:
UITableView().emptyView = EmptyPageView.mix(view: customView)
視圖關係
**特性: **
- 支持鏈式調用.
- 元素支持高度自定義.
- 一樣依照自定義視圖的標準實現.
ps: 徹底等同於提早寫好的自定義模板視圖.
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
模板視圖中總結起來只有三種配置函數:
約束配置函數: func change(...) -> Self
約束函數具體可配置項採用枚舉的形式限定.(以避免改變/衝突自適應高度相關約束)
enum HSpaceType { } // 修改視圖水平方向上的間距
enum VSpaceType { } // 修改視圖垂直方向上的間距
enum HeightType { } // 修改視圖具體高度
例如:
standardView.change(hspace: .button, value: 80) .change(height: .button, value: 60) 複製代碼
控件配置函數: func set(...) -> Self
提供了簡單的文本/字體/圖片/顏色配置.例如:
standardView.set(title: "Connection failure", color: UIColor.black, font: UIFont.boldSystemFont(ofSize: 24)) 複製代碼
控件自定義配置函數: 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) }) 複製代碼
視圖混合函數func mix()
:
該函數由 EmptyPageContentViewProtocol 協議默認實現.
做用: 將視圖約束至 backgroundView 上
ps: 別忘了...
項目開源連接: Github/EmptyPage
我的博客連接: 四方