爲了良好的交互體驗,相信你們在對待
scrollView
無數據時的提示頁都會使用一些第三方來定製,最典型的就是使用DZNEmptyDataSet。可是每一個界面都寫一堆與DZNEmptyDataSetDelegate
,DZNEmptyDataSetSource
相關的代碼就不太好,那通常狀況下天然的就會採用繼承的方式來避免。而Swift除了能夠面向對象編程,它還能夠面向協議編程。那可不能夠也用協議來解決狀況呢?嘿嘿,這個能夠有,那咱們接下來就來試試怎麼經過協議的方式來避免上述狀況,而且實現一行代碼添加空白頁功能git
ps: 目前 LXFProtocolTool 已更新屢次,代碼實現已有較大差異,有興趣的同窗能夠在閱讀完本文後再看看具體的代碼實現 EmptyDataSetablegithub
若是對面向協議有疑問的同窗能夠看下我以前的兩篇文章編程
以前的文章中提到了,協議除了起規範做用,還有別一個用處,就是賦予能力。咱們如今的目的就是讓目標控制器或者目標視圖在遵照咱們的協議後,就能夠有實現空白頁的功能。微信
// MARK:- 空視圖佔位協議
public protocol LXFEmptyDataSetable {
}
複製代碼
肯定咱們面向的類,通常tableView
或者collectionView
都是寫在控制器裏,那咱們面向的類就規定爲UIViewController
,或許也有人寫在UIView
裏,不過這裏先按UIViewController
來寫吧閉包
// MARK:- UIViewController - 空視圖佔位協議
public extension LXFEmptyDataSetable where Self : UIViewController {
// 三、的實現的方法寫在這裏
}
複製代碼
將scrollView
傳遞進來,讓咱們定義的方法來暗地裏作些操做ide
func lxf_EmptyDataSet(_ scrollView: UIScrollView) {
scrollView.emptyDataSetDelegate = self
scrollView.emptyDataSetSource = self
}
複製代碼
在三、定義功能方法
中將delegate
和source
設置爲了self
,而協議是沒法遵照再次遵照其它協議的,那讓什麼來遵照對應的協議呢?要明白這裏的self
指的是UIViewController
,考慮到UIView
的可能,這裏我就讓萬物對象之父NSObject
來遵照,並實現對應的數據源方法和代理方法post
extension NSObject : DZNEmptyDataSetDelegate, DZNEmptyDataSetSource {
public func image(forEmptyDataSet scrollView: UIScrollView!) -> UIImage! {
// 返回提示圖片
}
public func title(forEmptyDataSet scrollView: UIScrollView!) -> NSAttributedString! {
// 設置富文本標題
}
public func verticalOffset(forEmptyDataSet scrollView: UIScrollView!) -> CGFloat {
// 設置縱向偏移
}
}
複製代碼
經過上述步驟後,只要讓UIViewController
遵照咱們的協議,再調用一下lxf_EmptyDataSet
方法就能夠實現數據空白頁了。可是,這樣直接寫死的方式很很差,有時候一些場景是須要咱們作出定製的,那怎麼實現定製呢?協議又不能有本身的變量來存放咱們的定製。ui
這裏先作出一個限定,咱們要使用重載方法來完成該功能,實現便可高定製,又可以使用默認定製。
回到剛剛的話題,使用UserDefaults來實現能夠嗎?能夠,可是比較麻煩,由於UserDefaults是單例,整個進程共用這一份資源,若是你當前controller
遵照了咱們的協議LXFEmptyDataSetable
並作出了定製,那麼當下一個controller
在遵照協議後使用了默認定製
時,那你要怎麼辦?還要區分scrollView
,那就得保存當前scrollView
,在退出當前controller
後還要把對應的東西置空。好咯好咯,那你說到底要怎麼搞才最合適?
解決方案:拓展
UIScrollView
!!!有沒有發現?,很是地恰巧,咱們定義的方法lxf_EmptyDataSet
須要外界將UIScrollView
傳遞進來,在DZNEmptyDataSet
的數據源方法和代理方法也有scrollView
。那讓UIScrollView
來攜帶咱們的定製就好啦。
這裏我定義了經常使用的定製相關的枚舉
public enum LXFEmptyDataSetAttributeKeyType {
/// 縱向偏移(-50) CGFloat
case verticalOffset
/// 提示語(暫無數據) String
case tipStr
/// 提示語的font(system15) UIFont
case tipFont
/// 提示語顏色(D2D2D2) UIColor
case tipColor
/// 提示圖(LXFEmptyDataPic) UIImage
case tipImage
/// 容許滾動(true) Bool
case allowScroll
}
複製代碼
爲UIScrollView
定義一個定製相關的屬性字典
extension UIScrollView {
private struct AssociatedKeys {
static var lxf_emptyAttributeDict:[LXFEmptyDataSetAttributeKeyType : Any]?
}
/// 屬性字典
var lxf_emptyAttributeDict: [LXFEmptyDataSetAttributeKeyType : Any]? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.lxf_emptyAttributeDict) as? [LXFEmptyDataSetAttributeKeyType : Any]
}
set {
objc_setAssociatedObject(self, &AssociatedKeys.lxf_emptyAttributeDict, newValue as [LXFEmptyDataSetAttributeKeyType : Any]?, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
複製代碼
這裏咱們讓外界經過閉包的方式來定製本身的空白頁
// MARK:- UIViewController - 空視圖佔位協議
public extension LXFEmptyDataSetable where Self : UIViewController {
func lxf_EmptyDataSet(_ scrollView: UIScrollView, attributeBlock: (()->([LXFEmptyDataSetAttributeKeyType : Any]))? = nil) {
scrollView.lxf_emptyAttributeDict = attributeBlock != nil ? attributeBlock!() : nil
scrollView.emptyDataSetDelegate = self
scrollView.emptyDataSetSource = self
}
}
複製代碼
這裏以返回提示圖片的方法爲例吧
public func image(forEmptyDataSet scrollView: UIScrollView!) -> UIImage! {
guard let tipImg = scrollView.lxf_emptyAttributeDict?[.tipImage] as? UIImage else {
return UIImage(named: "LXFEmptyDataPic")
}
return tipImg
}
複製代碼
class LXFEmptyDemoController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
initUI()
}
}
extension LXFEmptyDemoController: LXFEmptyDataSetable {
fileprivate func initUI() {
let tableView = UITableView()
// ...
// 高定製
self.lxf_EmptyDataSet(tableView) { () -> ([LXFEmptyDataSetAttributeKeyType : Any]) in
return [
.tipStr:"喲喲喲",
.verticalOffset:-150,
.allowScroll: false
]
}
// 默認定製
// self.lxf_EmptyDataSet(tableView)
}
}
複製代碼
我對這個過程進行一次整理,並作成一個名爲 LXFProtocolTool 的庫並上傳至gitHub。可使用Cocoapods
的方式來安裝使用
pod 'LXFProtocolTool'
複製代碼
我也將 iOS - Swift 面向協議編程(二) 中說起的經過協議便捷加載xib的功能也集成了進來。你們能夠根據本身的須要在Podfile寫明要安裝的功能
pod 'LXFProtocolTool/LXFNibloadable'
複製代碼
pod 'LXFProtocolTool/LXFEmptyDataSetable'
複製代碼
建立這個庫的目的是爲了經過協議的方式來方便快捷地實現一些的實用功能,目前功能很少,不過日後會逐漸增長,或許你有什麼想實現的功能也能夠提出來,喜歡的就給個Star鼓勵下我吧 🚀 🚀 🚀