StatefulUI
一个协议,允许 UIViewController
或 UIView
根据内容、加载、错误或空状态呈现占位符视图。
概览
在联网应用程序中,视图控制器或自定义视图通常有以下需要通知用户的状态
- 加载: 内容正在通过网络加载。
- 内容: 内容可用并展示给用户。
- 空: 当前没有可展示的内容。
- 错误: 下载内容时发生错误。
尽管这个流程听起来可能很简单,但有很多情况会导致一个相当大的决策树。
StatefulViewController
是这个特定决策树的具体实现。(如果想要创建自己的修改版,可能会对用于显示和隐藏视图的状态机感兴趣。)
使用方法
本指南描述了
StatefulViewController
协议在UIViewController
上的使用。但您也可以在UIViewController
的任何子类(如UITableViewController
或UICollectionViewController
)以及您的自定义UIView
子类上采用StatefulViewController
协议。
首先,确保您的视图控制器采用 StatefulViewController
协议。
class MyViewController: UIViewController, StatefulViewController {
// ...
}
然后,在 viewDidLoad
中配置 loadingView
、emptyView
和 errorView
属性(由 StatefulViewController
协议提供)。您可以使用提供的默认视图,这些视图可以通过多种方式配置(请注意,其中一些接受 delegate
以处理按钮点击的回调)。
override func initializeEmptyStateViews() {
emptyView = StateEmptyView.load(subtitle: "No items found", delegate: self)
errorView = StateErrorView.load(delegate: self)
loadingView = StateLoadingView.load()
}
之后,只需告诉视图控制器何时内容正在加载,StatefulViewController
将会为您显示和隐藏正确的加载、错误和空视图。
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
loadDeliciousWines()
}
func loadDeliciousWines() {
startLoading()
let url = NSURL(string: "http://example.com/api")
let session = NSURLSession.sharedSession()
session.dataTaskWithURL(url) { [weak self] (let data, let response, let error) in
self?.endLoading(error: error)
}.resume()
}
生命周期
StatefulViewController 调用 hasContent
方法以检查是否存在任何可显示的内容。如果您在自己的类中没有重写此方法,则 StatefulViewController
将始终假定有内容要显示。已经为 UITableView
、UICollectionView
及其控制器变体提供了默认实现。
func hasContent() -> Bool {
return datasourceArray.count > 0
}
可选地,即使在内容已经显示的情况下,您可能也想对错误做出响应。在这种情况下,StatefulViewController
不会显示其 errorView
,因为已经有内容可以显示。
例如,要显示自定义弹窗或其他不干扰的错误消息,请使用 handleErrorWhenContentAvailable:
手动将错误显示给用户。
func handleErrorWhenContentAvailable(error: ErrorType) {
let alert = UIAlertController(title: "Ooops", message: "Something went wrong.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
presentViewController(alert, animated: true)
}
类似地,即使已显示内容,您也可能想要向用户显示活动。实现 subtleActivityIndicatorView
属性并提供活动指示器
var subtleActivityIndicatorView: ActivityIndicatingView? {
return footerActivityIndicator
}
自定义占位视图的内边距
默认情况下,StatefulViewController 以全屏方式(即从父视图顶部、底部、左侧和右侧的0内边距)显示所有配置的占位视图。如果占位视图应具有自定义内边距,则配置的占位视图可以遵守 StatefulPlaceholderView
协议并重写 placeholderViewInsets
方法以返回自定义边缘内边距。
class MyPlaceholderView: UIView, StatefulPlaceholderView {
func placeholderViewInsets() -> UIEdgeInsets {
return UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
}
}
视图状态机
注意:以下部分仅适用于希望创建与上述流程不同的有状态控制器的用户。
您还可以使用底层视图状态机创建与您自定义显示/隐藏视图流程类似的实现。
let stateMachine = ViewStateMachine(view: view)
// Add states
stateMachine["loading"] = loadingView
stateMachine["other"] = otherView
// Transition to state
stateMachine.transitionToState(.View("loading"), animated: true) {
println("finished switching to loading view")
}
// Hide all views
stateMachine.transitionToState(.None, animated: true) {
println("all views hidden now")
}
安装
CocoaPods
在您的Podfile中添加以下行。
pod "StatefulUI", "~> 1.0"
然后使用CocoaPods 1.4或更高版本运行pod install
。
贡献
- 创建出一些精彩的东西,优化代码,添加一些功能,等等(这部分是最难的)。
- Fork它
- 创建新分支以进行更改
- 将所有更改提交到您的分支
- 提交pull request
鸣谢
StatefulUI 是由 David Jennes 提供的,它基于 StatefulViewController 的分支,最初由 @schuchalexander 编写。
授权协议
StatefulUI 在MIT授权协议下可用。有关更多信息,请参阅LICENSE文件。