Swift 空資料介面顯示模組封裝實現
一個Swift語言封裝的EmptyView顯示庫,可作用於WKWebView、UITableView、UICollectionView
示例
-
WKWebView
-
UITableView
- UICollectionView
引言:
專案開發過程中當網路斷開或者資料獲取失敗導致的介面顯示為空的情況下,我們常會用到圖片加文字加重新整理按鈕、文字加重新整理按鈕或者純文字提醒的空介面顯示,所以對該功能實現的封裝封裝就顯得很有必要。
該技術封裝模組使用Swift語言,參考OC封裝模組的內部實現邏輯,利用runtime的系統方法交換機制,實現在WKWebView網頁載入介面、UITableView、UICollectionView列表檢視等介面資料獲取失敗情況下的提醒顯示和重新整理操作功能。
一:內部實現原理
1、通過runtime key值關聯HDEmptyView顯示物件
建立UIScrollView的extension物件UIScrollView+Empty類,通過runtime key值關聯HDEmptyView顯示介面物件ly_emptyView ,該物件可根據呼叫介面的引數設定來控制空介面顯示的內容、佈局樣式、顏色等。
struct RuntimeKey {
static let kEmptyViewKey = UnsafeRawPointer.init(bitPattern: "kEmptyViewKey".hashValue)
}
public var ly_emptyView: HDEmptyView? {
set {
objc_setAssociatedObject(self, RuntimeKey.kEmptyViewKey!, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
for view in self.subviews {
if view.isKind(of: HDEmptyView.classForCoder()) {
view.removeFromSuperview()
}
}
self.addSubview(ly_emptyView!)
self.ly_emptyView?.isHidden = true
}
get {
return objc_getAssociatedObject(self, RuntimeKey.kEmptyViewKey!) as? HDEmptyView
}
}
2、WKWebView 呼叫顯隱方法
如果是WKWebView的空資料介面顯示,根據介面載入成功或失敗的情況,呼叫顯示/隱藏空介面方法
public func ly_showEmptyView() {
self.ly_emptyView?.superview?.layoutSubviews()
self.ly_emptyView?.isHidden = false
//始終保持顯示在最上層
if self.ly_emptyView != nil {
self.bringSubview(toFront: self.ly_emptyView!)
}
}
public func ly_hideEmptyView() {
self.ly_emptyView?.isHidden = true
}
3、列表檢視顯隱控制
如果是UITableView、UICollectionView則根據DataSource判斷是否自動顯示emptyView
首先獲取當前列表檢視上cell的個數
//MARK: - Private Method
fileprivate func totalDataCount() -> NSInteger {
var totalCount: NSInteger = 0
if self.isKind(of: UITableView.classForCoder()) {
let tableView = self as? UITableView
if (tableView?.numberOfSections)! >= 1 {
for section in 0...(tableView?.numberOfSections)!-1 {
totalCount += (tableView?.numberOfRows(inSection: section))!
}
}
}
else if self.isKind(of: UICollectionView.classForCoder()) {
let collectionView = self as? UICollectionView
if (collectionView?.numberOfSections)! >= 1 {
for section in 0...(collectionView?.numberOfSections)!-1 {
totalCount += (collectionView?.numberOfItems(inSection: section))!
}
}
}
return totalCount
}
然後根據cell的個數判斷是否顯示 emptyView
fileprivate func getDataAndSet() {
if self.totalDataCount() == 0 {
show()
} else {
hide()
}
}
fileprivate func show() {
if self.ly_emptyView?.autoShowEmptyView == false {
self.ly_emptyView?.isHidden = true
return
}
ly_showEmptyView()
}
fileprivate func hide() {
if self.ly_emptyView?.autoShowEmptyView == false {
self.ly_emptyView?.isHidden = true
return
}
ly_hideEmptyView()
}
4、列表檢視的方法交換與介面重新整理顯示
private static let swizzleMethod: Void = {
//insertSections
let originalSelector = #selector(insertSections(_:with:))
let swizzledSelector = #selector(ly_insertSections(_:with:))
HDRunTime.exchangeMethod(selector: originalSelector, replace: swizzledSelector, class: UITableView.self)
//deleteSections
let originalSelector1 = #selector(deleteSections(_:with:))
let swizzledSelector1 = #selector(ly_deleteSections(_:with:))
HDRunTime.exchangeMethod(selector: originalSelector1, replace: swizzledSelector1, class: UITableView.self)
//insertRows
let originalSelector2 = #selector(insertRows(at:with:))
let swizzledSelector2 = #selector(ly_insertRowsAtIndexPaths(at:with:))
HDRunTime.exchangeMethod(selector: originalSelector2, replace: swizzledSelector2, class: UITableView.self)
//deleteRows
let originalSelector3 = #selector(deleteRows(at:with:))
let swizzledSelector3 = #selector(ly_deleteRowsAtIndexPaths(at:with:))
HDRunTime.exchangeMethod(selector: originalSelector3, replace: swizzledSelector3, class: UITableView.self)
//reload
let originalSelector4 = #selector(reloadData)
let swizzledSelector4 = #selector(ly_reloadData)
HDRunTime.exchangeMethod(selector: originalSelector4, replace: swizzledSelector4, class: UITableView.self)
}()
//section
@objc func ly_insertSections(_ sections: NSIndexSet, with animation: UITableViewRowAnimation) {
ly_insertSections(sections, with: animation)
getDataAndSet()
}
@objc func ly_deleteSections(_ sections: NSIndexSet, with animation: UITableViewRowAnimation) {
ly_deleteSections(sections, with: animation)
getDataAndSet()
}
//row
@objc func ly_insertRowsAtIndexPaths(at indexPaths: [IndexPath], with animation: UITableViewRowAnimation){
ly_insertRowsAtIndexPaths(at: indexPaths, with: animation)
getDataAndSet()
}
@objc func ly_deleteRowsAtIndexPaths(at indexPaths: [IndexPath], with animation: UITableViewRowAnimation){
ly_deleteRowsAtIndexPaths(at: indexPaths, with: animation)
getDataAndSet()
}
//reloadData
@objc func ly_reloadData() {
self.ly_reloadData()
self.getDataAndSet()
}
二:使用方法
1、建立 HDEmptyView 介面顯示物件
//建立方式一:Block回撥
let emptyV:HDEmptyView = HDEmptyView.emptyActionViewWithImageStr(imageStr: "net_error_tip", titleStr: "暫無資料,點選重新載入", detailStr: "", btnTitleStr: "點選重新整理") {
print("點選重新整理")
weakSelf?.reloadDataWithCount(count: 4)
}
//建立方式二:target/action
let emptyV:HDEmptyView = HDEmptyView.emptyActionViewWithImageStr(imageStr: "net_error_tip", titleStr: "暫無資料,點選重新載入", detailStr: "", btnTitleStr: "點選重新整理", target: self, action: #selector(reloadBtnAction)) as! HDEmptyView
2、設定顯示引數屬性
emptyV.titleLabTextColor = UIColor.red
emptyV.actionBtnFont = UIFont.systemFont(ofSize: 19)
emptyV.contentViewOffset = -50
emptyV.actionBtnBackGroundColor = .white
emptyV.actionBtnBorderWidth = 0.7
emptyV.actionBtnBorderColor = UIColor.gray
emptyV.actionBtnCornerRadius = 10
3、賦值給當前顯示物件的ly_emptyView
webView.scrollView.ly_emptyView = emptyV
tableView.ly_emptyView = emptyV
collectionView.ly_emptyView = emptyV
//設定點選空白區域是否有重新整理操作
self.webView.scrollView.ly_emptyView?.tapContentViewBlock = {
//weakSelf!.loadingURL(urltring: "http://news.baidu.com/")
}
4、自定義空資料介面顯示
//自定義空資料介面顯示
func setupMyEmptyView() {
let emptyView: MyEmptyView = Bundle.main.loadNibNamed("MyEmptyView", owner: self, options: nil)?.last as! MyEmptyView
emptyView.reloadBtn.addTarget(self, action: #selector(reloadBtnAction(_:)), for: UIControlEvents.touchUpInside)
emptyView.frame = view.bounds
//空資料介面顯示
let emptyV:HDEmptyView = HDEmptyView.emptyViewWithCustomView(customView: emptyView) as! HDEmptyView
tableView.ly_emptyView = emptyV
tableView.ly_emptyView?.tapContentViewBlock = {
print("點選介面空白區域")
}
tableView.ly_showEmptyView()
}
注意事項:
是否自動顯隱EmptyView的引數 autoShowEmptyView 預設設定是true,列表檢視會根據介面cell的count數量自動顯隱空介面。
當設定成false時只能手動呼叫 ly_showEmptyView() 和 ly_hideEmptyView() 方法進行顯隱操作
相關文章
- iOS資料上報模組封裝方案iOS封裝
- 封裝模組實現商品增刪改查封裝
- JavaScript 模組封裝JavaScript封裝
- Vue — 請求模組、api模組封裝VueAPI封裝
- vue - axios網路封裝模組VueiOS封裝
- Lua封裝函式模組並由其他模組呼叫封裝函式
- 基於IIC介面的OLED資料顯示
- 【IDL】滑鼠資訊顯示介面(同理可實現鷹眼圖等)
- Vue響應式資料: Observer模組實現VueServer
- Swift keychain 官方封裝DemoSwiftAI封裝
- 封裝介面封裝
- 基於SPI/IIC介面的OLED資料顯示
- 8.7 一個模組的封裝過程封裝
- vue專案的網路模組封裝Vue封裝
- React Native 原生模組封裝:支付寶示例React Native封裝
- Swift + RxSwift MVVM 模組化專案實踐SwiftMVVM
- WPF/C#:如何將資料分組顯示C#
- C++庫封裝JNI介面——實現java呼叫c++C++封裝Java
- 介面自動化之實現日誌記錄封裝封裝
- java實現將資料庫資料轉化成excel表格顯示出來Java資料庫Excel
- 帝國CMS安裝介面不能正常顯示
- C++ 使用 hiredis 封裝redis 的資料獲取介面C++Redis封裝
- [hyperf]關於資料返回封裝的另一種實現思考封裝
- FPGA影像採集與顯示專案(一)帶LOGO的VGA顯示模組FPGAGo
- 手撕Vuex-安裝模組資料Vue
- Swift 專案的模組化Swift
- Geoserver + MySQL實現圖層顯示和文字顯示ServerMySql
- 簡訊介面封裝封裝
- WPF/C#:顯示分組資料的兩種方式C#
- 基於STM32的OLED的SPI介面資料顯示
- swift 定位封裝一句話使用Swift封裝
- 評論模組 – 後端資料庫設計及功能實現後端資料庫
- 評論模組 - 後端資料庫設計及功能實現後端資料庫
- swift 混編 oc 斷點時資料只有變數名稱不顯示值Swift斷點變數
- 第八講、Vue3.x中的模組化以及封裝Storage實現todolist 待辦事項Vue封裝
- element table不顯示任何資料,無資料倒是顯示出無資料的了
- [譯] Swift 模組中的 API 汙染SwiftAPI
- PyQT5之PyQtGraph實時資料顯示QT