DBEmptyState helps you to manage your empty/error/whatever states inside your TableView and CollectionView. You can define states and representations which get displayed once your state is active.
Inside your ViewController, create and store a EmptyTableViewAdapter
and a StateMachine
.
let emptyState = StateMachine<EmptyState>(initialState: .initial)
var emptyDataSet: EmptyContentTableViewAdapter<EmptyState>!
override func viewDidLoad() {
super.viewDidLoad()
emptyDataSet = EmptyContentTableViewAdapter(view: tableView, stateManaging: emptyState, dataSource: self)
//Hide empty tableView skeleton cells, when empty content gets displayed
emptyDataSet = EmptyContentTableViewAdapter(view: tableView, stateManaging: emptyState, dataSource: self,
whenStateChanges: EmptyContentTableViewAdapter.hideSkeletonCellsWhenEmptyStateIsVisable)
}
EmptyContentCollectionViewAdapter
works exaclty as EmptyContentTableViewAdapter
.
let emptyState = StateMachine<EmptyState>(initialState: .initial)
var emptyDataSet: EmptyContentCollectionViewAdapter<EmptyState>!
override func viewDidLoad() {
super.viewDidLoad()
emptyDataSet = EmptyContentCollectionViewAdapter(view: collectionView, stateManaging: emptyState, dataSource: self)
}
Provide content for the states you want by implementing at least EmptyContentDataSource
.
extension ExampleViewController: EmptyContentDataSource {
func emptyContent(for state: EmptyState) -> EmptyContent? {
switch state {
case .initial:
return EmptyContent(title: "Initial State", subtitle: "This is an initial state with subtitles", image: UIImage(named: "image.png"))
case .loading:
return .customPresentation // needed when you want to display only a custom view
case .error:
return EmptyContent(title: "Error")
default:
return nil
}
}
}
By implementing CustomEmptyViewDataSource
and returning a new view for a given state you can override the default layout with a custom view.
extension ExampleViewController: CustomEmptyViewDataSource {
func customView(for state: EmptyState, with content: EmptyContent) -> UIView? {
switch state {
case .loading:
let spinner = UIActivityIndicatorView(activityIndicatorStyle: .gray)
spinner.startAnimating()
return spinner
default:
return nil
}
}
}
If you want to add a button into you empty this is possible by implementing ActionButtonDataSource
extension ExampleViewController: ActionButtonDataSource {
func button(for state: EmptyState) -> ButtonModel? {
switch state {
case .error:
return ButtonModel(title: "Retry", action: {})
default:
return nil
}
}
}
In many cases you descide to implement just of of the mentioned dataSources. When doing so you need to use the fitting init()
on the ViewAdapter. See the following example to find the right initializer:
//When only implementing EmptyContentDataSource
let viewDatapter = EmptyContentTableViewAdapter(tableView: tableView, stateManaging: emptyState, emptyContentDataSource: self)
//When implementing EmptyContentDataSource & CustomEmptyViewDataSource
let viewDatapter = EmptyContentTableViewAdapter(tableView: tableView, stateManaging: emptyState, emptyContentCustomViewDataSource: self)
//When your dataSources are implemented by different types
let viewDatapter = EmptyContentTableViewAdapter(tableView: tableView, stateManaging: emptyState, emptyContentDataSource: self, customViewDataSource: firstOtherType, buttonDataSource: secondOtherType)
Note: All initializers are available for EmptyContentCollectionViewAdapter
as well.
- iOS 9.0+
- Xcode 10.0+
- Swift 4.0+
Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
Specify the following in your Cartfile
:
github "dbsystel/DBEmptyState" == 0.4.0
Feel free to submit a pull request with new features, improvements on tests or documentation and bug fixes. Keep in mind that we welcome code that is well tested and documented.
Lukas Schmidt (Mail, @lightsprint09)
DBEmptyState is released under the MIT license. See LICENSE for details.