Monviso
is a framework which gives data source structure for UITableView
, UICollectionView
and UIPageViewController
.
You create a data source, you customize it with closures, you insert contents in provided structures and you set data source of your client object: that's it!
What is more, this framework provides an automated system to apply content updates to UITableView
and UICollectionView
animating transitions.
In this example I will use UITableView
, but UICollectionView
is very similar.
Say you have a UITableViewController
subclass.
class TableViewController: UITableViewController {
}
Start creating a data source.
import Monviso
class TableViewController: UITableViewController {
private let dataSource = TableViewDataSource()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = dataSource
}
}
You need to provide content to you user.
import Monviso
struct Flower {
let name: String
}
class TableViewController: UITableViewController {
private let flowers = [ Flower(name: "Tulip"), Flower(name: "Rose") ]
private let dataSource: TableViewDataSource()
override func viewDidLoad() {
super.viewDidLoad()
dataSource.content.sections = [ TableViewDataSource.Section(identifier: "flowers", items: flowers, header: "Flowers") ]
tableView.dataSource = dataSource
}
}
You data source needs to know how to display content.
import Monviso
struct Flower {
let name: String
}
class TableViewController: UITableViewController {
private let flowers = [ Flower(name: "Tulip"), Flower(name: "Rose") ]
private let dataSource: TableViewDataSource {
let dataSource = TableViewDataSource()
dataSource.cellFactory.creator = { item, indexPath, tableView in
if let flower = item as? Flower {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel!.text = flower.name
return cell
}
else {
throw AccessError.noUI(for: item)
}
}
return dataSource
}
override func viewDidLoad() {
super.viewDidLoad()
dataSource.content.sections = [ TableViewDataSource.Section(identifier: "flowers", items: flowers, header: "Flowers") ]
tableView.dataSource = dataSource
}
}
That's all. This is the minimal setup to display static contents. If you would like to update contents with animation, you should change a couple of things. First of all, you have to make your contents able to detect updates using embedded Ferrara.
import Monviso
import Ferrara
struct Flower: Identifiable, Matchable, Equatable {
let identifier: String
let name: String
public static func ==(lhs: Flower, rhs: Flower) -> Bool {
return lhs.identifier == rhs.identifier && lhs.name == lhs.name
}
}
Then, you should apply changes to your client.
var flowers = [ Flower(identifier: "tulip", name: "Tulip"), Flower(identifier: "rose", name: "Rose") ]
func updateToEmojiFlowers() {
flowers = [ Flower(identifier: "tulip", name: "๐ท"), Flower(identifier: "rose", name: "๐น") ]
let update = dataSource.content.update(sections: [ TableViewDataSource.Section(identifier: "flowers", items: flowers, header: "Flowers") ])
tableView.apply(update: update)
}
Nothing more than this.
Monviso
can help you when you need to display a finite number of pages inside a UIPageViewController
.
Start creating a data source.
import Monviso
class PageViewController: UIPageViewController {
let dataSource = PageViewControllerDataSource()
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = pageDataSource
}
}
You need to provide content to you user.
import Monviso
struct Flower {
let name: String
}
class PageViewController: UIPageViewController {
private let flowers = [ Flower(name: "Tulip"), Flower(name: "Rose") ]
let dataSource = PageViewControllerDataSource()
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = pageDataSource
}
}
You data source needs to know how to display content and how to associate view controllers to content index.
import Monviso
struct Flower: Equatable {
let name: String
public static func ==(lhs: Flower, rhs: Flower) -> Bool {
return lhs.name == lhs.name
}
}
class PageViewController: UIPageViewController {
private let flowers = [ Flower(name: "Tulip"), Flower(name: "Rose") ]
private let dataSource: PageViewControllerDataSource {
let dataSource = PageViewControllerDataSource()
dataSource.viewControllerFactory.creator = { item, index, _ in
return FlowerViewController(flower: Flower)
}
dataSource.indexer = { viewController, content in
if let viewController = viewController as? FlowerViewController,
let index = (content as! [Flower]).index(of: viewController.flower)
{
return index
}
else {
throw AccessError.invalidOutput(nil)
}
}
return dataSource
}
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = pageDataSource
}
}
Now you need to inform you page view controller to display first page.
import Monviso
struct Flower: Equatable {
let name: String
public static func ==(lhs: Flower, rhs: Flower) -> Bool {
return lhs.name == lhs.name
}
}
class PageViewController: UIPageViewController {
private let flowers = [ Flower(name: "Tulip"), Flower(name: "Rose") ]
private let dataSource: PageViewControllerDataSource {
let dataSource = PageViewControllerDataSource()
dataSource.viewControllerFactory.creator = { item, index, _ in
return FlowerViewController(flower: Flower)
}
dataSource.indexer = { viewController, content in
if let viewController = viewController as? FlowerViewController,
let index = (content as! [Flower]).index(of: viewController.flower)
{
return index
}
else {
throw AccessError.invalidOutput(nil)
}
}
return dataSource
}
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = pageDataSource
let update = try! pageDataSource.update(content: flowers, toShowPages: 0...0, in: self)
apply(update: update, animated: false)
}
}
That's all.
Now, implementing page swap methods is trivial.
func goToNextPage(animated: Bool = true) throws {
let indexes = try pageDataSource.indexesOfContent(displayedIn: self)
let index = indexes.first! + 1
let update = try! pageDataSource.update(toShowPages: index...index, in: self)
apply(update: update, animated: animated)
}
func canGoToNextPage() -> Bool {
if let indexes = try? pageDataSource.indexesOfContent(displayedIn: self), let lastIndex = indexes.last
{
return lastIndex < pageDataSource.content.count - 1
}
else {
return false
}
}
- iOS 8.2 SDK.
- Minimum deployment target: iOS 8.
Monviso
is available through CocoaPods. To install
it, simply add the following line to your Podfile:
pod "Monviso"
Marco Muccinelli, muccymac@gmail.com
Monviso
is available under the MIT license. See the LICENSE file for more info.
Monte Viso or Monviso, is the highest mountain of the Cottian Alps. It is located in Italy close to the French border.On a very clear day it can be seen from the spires of the Milan Cathedral. On the northern slopes of Monte Viso are the headwaters of the Po, the longest Italian river. Po river source, data source... that's why ;)