EmptyPage(空白頁組件)原理與使用

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, 超級簡單.

  1. UIScrollView添加emptyView對象作為空白頁實(shí)例:
    public extension UIScrollView {
      public var emptyView: UIView?
    }
    
  2. 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()
    
  3. 在數(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)
      }
    
  4. 使用

    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'
  1. 自定義視圖
    • 僅支持autolayout布局模式

      不使用 autolayout 模式:

      1. pod 'EmptyPage/Core'

      2. 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)系
  2. 內(nèi)置模板視圖

    **特性: **

    1. 支持鏈?zhǔn)秸{(diào)用.
    2. 元素支持高度自定義.
    3. 同樣依照自定義視圖的標(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è)人博客鏈接: 四方田

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 1、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明AGI閱讀 16,009評論 3 119
  • 我的媽媽,今年56歲,頭發(fā)半白,是一個(gè)讀到小學(xué)二年級就輟學(xué)回家干農(nóng)活的女人。她個(gè)頭不高,身材中等,文化水平不高,沒...
    空中之鳥閱讀 382評論 0 0
  • 對于我們的眼睛,不是缺少美,而是缺少發(fā)現(xiàn)——看Matizki的攝影作品,你會更深刻地體悟這句話。 Matizki是...
    荻子荻子閱讀 422評論 0 2
  • ——魏君學(xué)習(xí)非暴力溝通心得 “我這樣做對嗎?” “我這衣服漂亮嗎?” “他讓我感到自己很有價(jià)值。” “他會怎么看我...
    魏君NVC閱讀 399評論 2 2