分享一个轮子 - 空白页库【Swift】

2,944 阅读3分钟

今看到GitHub推荐了个Swift的空白页展示库;本着善用轮子,提高生产力的原则,下载了源码看了下,分享给大家。

我们在使用App的时候,经常会出现因为请求不成功 / 数据错误等原因,在应用中显示一个空白页,提示用户进行操作。提示的内容包括:1.图片, 2.标题,3.提示正文,4.操作按钮。在这个库,中这些提示内容都包含在EmptyStateView里。

EmptyStateView

这个视图定义了空白页要显示的内容以及操作。内部定义了一个ViewModel来显示内容。EmptyStateView遵循NibLoadableNibLoadable是让实例对象从Nib中加载创建。

//视图内容
struct ViewModel {
    var image: UIImage?
    var title: String?
    var description: String?
    var titleButton: String?
}

var viewModel = ViewModel() {
    didSet { fillView() }
}
//空白页格式化
var format = EmptyStateFormat() {
    didSet { updateUI() }
}

//操作回调
var actionButton: ((UIButton)->())?

EmptyState

在使用这个库的时候,我们只需要设置viewemptyState.delegateemptyState.dataSource,让代理对象遵循EmptyStateDelegateEmptyStateDataSource,就可以调用showHide方法显示与隐藏空白页。

view.emptyState.delegate = self
view.emptyState.dataSource = self

那么,viewemptyState是怎么出现的?作者在这里使用了关联对象,动态的将EmptyState实例关联给viewemptyState

enum ViewAssociatedKeys {
    static var emptyState = "emptyState"
}

public extension UIView {
    
    var emptyState: EmptyState! {
        get {
            guard let saved = ao_get(pkey: &ViewAssociatedKeys.emptyState) as? EmptyState else {
                self.emptyState = EmptyState(inView: self)
                return self.emptyState
            }
            return saved
        }
        set { ao_set(newValue ?? EmptyState(inView: self), pkey: &ViewAssociatedKeys.emptyState) }
    }
}

EmptyState是一个类,管理空白页的显示与隐藏。在这个类的实例创建的时候,就一并创建了EmptyStateView的实例,并且根据要显示空白页的视图(UITableView / UICollectionView)来显示,UITableView / UICollectionView里空白页都是直接设置为其背景视图

init(inView view: UIView?) {
    
    // 创建空白页
    emptyStateView = EmptyStateView.view
    emptyStateView.isHidden = true
    emptyStateView.actionButton = { [weak self] (button) in
        self?.didPressActionButton(button)
    }
    
    // 添加到要显示空白页的视图
    if let view = view as? UITableView {
        view.backgroundView = emptyStateView
        tableView = view
        separatorStyle = view.separatorStyle
    } else if let view = view as? UICollectionView {
        view.backgroundView = emptyStateView
    } else {
        emptyStateView.fixConstraintsInView(view)
    }
}

操作的响应事件,通过EmptyStateViewactionButton,传递给EmptyStatedidPressActionButton(),再传递到了EmptyStateDelegateemptyState()()(),将事件的处理交由了代理对象处理。

定制化显示 - CustomState

想要空白页显示不同的图片 / 标题 / 提示语,写个Enum,遵循CustomState,再由对应枚举值,返回遵循CustomState,要实现的image / title / description / titileButton,返回EmptyStateFormat的实例。EmptyStateView的实例会根据format属性,更新显示内容。

//EmptyStateView的format属性,设置其值,会更新UI.
var format = EmptyStateFormat() {
    didSet { updateUI() }
}

作者有个示例可以看下。

enum TableState: CustomState {
    
    case noNotifications
    case noBox
    case noCart
    case noFavorites
    case noLocation
    case noProfile
    case noSearch
    case noTags
    case noInternet
    case noIncome
    case inviteFriend
    
    var image: UIImage? {
        switch self {
        case .noNotifications: return UIImage(named: "Messages")
        case .noBox: return UIImage(named: "Box")
        case .noCart: return UIImage(named: "Cart")
        case .noFavorites: return UIImage(named: "Favorites")
        case .noLocation: return UIImage(named: "Location")
        case .noProfile: return UIImage(named: "Profile")
        case .noSearch: return UIImage(named: "Search")
        case .noTags: return UIImage(named: "Tags")
        case .noInternet: return UIImage(named: "Internet")
        case .noIncome: return UIImage(named: "Income")
        case .inviteFriend: return UIImage(named: "Invite")
        }
    }
    
    var title: String? {
        switch self {
        case .noNotifications: return "No message notifications"
        case .noBox: return "The box is empty"
        case .noCart: return "The cart is empty"
        case .noFavorites: return "No favorites"
        case .noLocation:  return "Where are you?"
        case .noProfile: return "Not logged In"
        case .noSearch: return "No results"
        case .noTags: return "No collections"
        case .noInternet: return "We’re Sorry"
        case .noIncome: return "No income"
        case .inviteFriend: return "Ask friend!"
        }
    }
    
    var description: String? {
        switch self {
        case .noNotifications: return "Sorry, you don't have any message. Please come back later!"
        case .noBox: return "You dont have any email!"
        case .noCart: return "Please, select almost one item to purchase"
        case .noFavorites: return "Select your favorite items first!"
        case .noLocation: return "We can't find your location"
        case .noProfile: return "Please register or log in first"
        case .noSearch: return "Please try another search item"
        case .noTags: return "Go to collect favorites products"
        case .noInternet: return "Our staff is still working on the issue for better experience"
        case .noIncome: return "You have no payment so contact your client"
        case .inviteFriend: return "You could borrow money from your network"
        }
    }
    
    var titleButton: String? {
        switch self {
        case .noNotifications: return "Search again?"
        case .noBox: return "Search again?"
        case .noCart: return "Go back"
        case .noFavorites: return "Go back"
        case .noLocation: return "Locate now!"
        case .noProfile: return "Log in now!"
        case .noSearch: return "Go back"
        case .noTags: return "Go shopping"
        case .noInternet: return "Try again?"
        case .noIncome: return "Request payment"
        case .inviteFriend: return "View contact"
        }
    }
}

当然也可以通过EmptyStateDataSource返回对应状态下要显示的内容。

链接

EmptyStateKit:github.com/alberdev/Em…