Skip to content

Instantly share code, notes, and snippets.

@SpaceboatDVLP
Last active January 11, 2019 18:48
Show Gist options
  • Save SpaceboatDVLP/55ec128ce8d217d0c5a76e1bd2f60ac6 to your computer and use it in GitHub Desktop.
Save SpaceboatDVLP/55ec128ce8d217d0c5a76e1bd2f60ac6 to your computer and use it in GitHub Desktop.
This is boilerplate for a static UIPageViewController built using Interface Builder. View Controllers are initialized in the IB with storyboard identifiers names as "Page" + PageNumber + "Controller". In this snippet, there are 3 view controllers in storyboard that correspond to pages (note the pageCount variable in ModelController).
//
// ModelController.swift
// PageViewShenanigans
//
// Created by Steve Looney on 9/7/17.
// Copyright © 2017 Spaceboat Development, LLC. All rights reserved.
//
import UIKit
/*
The controller serves as the data source for the page view controller; it therefore implements pageViewController:viewControllerBeforeViewController: and pageViewController:viewControllerAfterViewController:.
It also implements a custom method, viewControllerAtIndex: which is useful in the implementation of the data source methods, and in the initial configuration of the application.
*/
class ModelController: NSObject, UIPageViewControllerDataSource {
var vcArray:[UIViewController] = []
var pageCount = 3
override init() {
super.init()
// Create the ViewController data model
let storyboard = UIStoryboard(name: "Main", bundle: nil)
for i in 1...pageCount {
print("here's i: \(i)")
let pvc = storyboard.instantiateViewController(withIdentifier: "Page\(i)Controller")
vcArray.append(pvc)
}
}
func viewControllerAtIndex(_ index: Int, storyboard: UIStoryboard) -> UIViewController? {
// Return the data view controller for the given index.
if (self.vcArray.count == 0) {
// The vcArray doesn't exist yet. Build it.
for i in 1...pageCount {
// These pages correspond to UIViewControllers created in the interface building with identifiers conforming to naming "Page # Controller"
let pvc = storyboard.instantiateViewController(withIdentifier: "Page\(i)Controller")
vcArray.append(pvc)
}
} else if (index >= self.vcArray.count) {
// index surpasses the vcArray count, return nil signaling the end of the data
return nil
}
// Create a new view controller and pass suitable data.
//dataViewController.dataObject = self.pageData[index]
return vcArray[index]
}
func indexOfViewController(_ viewController: UIViewController) -> Int {
// Return the index of the given data view controller.
// For simplicity, this implementation uses a static array of model objects and the view controller stores the model object; you can therefore use the model object to identify the index.
return vcArray.index(of: viewController) ?? NSNotFound
}
// MARK: - Page View Controller Data Source
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
var index = self.indexOfViewController(viewController)
if index == NSNotFound {
return nil
}
index += 1
if index == self.pageData.count {
return nil
}
return self.viewControllerAtIndex(index, storyboard: viewController.storyboard!)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
var index = self.indexOfViewController(viewController)
if (index == 0) || (index == NSNotFound) {
return nil
}
index -= 1
return self.viewControllerAtIndex(index, storyboard: viewController.storyboard!)
}
}
//
// RootViewController.swift
// PageViewShenanigans
//
// Created by Steve Looney on 9/7/17.
// Copyright © 2017 Spaceboat Development, LLC. All rights reserved.
//
import UIKit
class RootViewController: UIViewController, UIPageViewControllerDelegate {
var pageViewController = UIPageViewController.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Configure the page view controller and add it as a child view controller.
self.pageViewController.delegate = self
self.pageViewController.dataSource = self.modelController
let startingViewController: UIViewController = self.modelController.viewControllerAtIndex(0, storyboard: self.storyboard!)!
let viewControllers = [startingViewController]
self.pageViewController.setViewControllers(viewControllers, direction: .forward, animated: false, completion: {done in })
//self.pageViewController!.dataSource = self.modelController
self.addChildViewController(self.pageViewController)
self.view.addSubview(self.pageViewController.view)
// Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
var pageViewRect = self.view.bounds
if UIDevice.current.userInterfaceIdiom == .pad {
pageViewRect = pageViewRect.insetBy(dx: 40.0, dy: 40.0)
}
self.pageViewController.view.frame = pageViewRect
self.pageViewController.didMove(toParentViewController: self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
var modelController: ModelController {
// Return the model controller object, creating it if necessary.
// In more complex implementations, the model controller may be passed to the view controller.
if _modelController == nil {
_modelController = ModelController()
}
return _modelController!
}
var _modelController: ModelController? = nil
// MARK: - UIPageViewController delegate methods
func pageViewController(_ pageViewController: UIPageViewController, spineLocationFor orientation: UIInterfaceOrientation) -> UIPageViewControllerSpineLocation {
print("SPINE LOCATION FOR WHAT")
if (orientation == .portrait) || (orientation == .portraitUpsideDown) || (UIDevice.current.userInterfaceIdiom == .phone) {
// In portrait orientation or on iPhone: Set the spine position to "min" and the page view controller's view controllers array to contain just one view controller. Setting the spine position to 'UIPageViewControllerSpineLocationMid' in landscape orientation sets the doubleSided property to true, so set it to false here.
let currentViewController = self.pageViewController.viewControllers![0]
let viewControllers = [currentViewController]
self.pageViewController.setViewControllers(viewControllers, direction: .forward, animated: true, completion: {done in })
self.pageViewController.isDoubleSided = false
return .min
}
// In landscape orientation: Set set the spine location to "mid" and the page view controller's view controllers array to contain two view controllers. If the current page is even, set it to contain the current and next view controllers; if it is odd, set the array to contain the previous and current view controllers.
let currentViewController = self.pageViewController.viewControllers![0]
var viewControllers: [UIViewController]
let indexOfCurrentViewController = self.modelController.indexOfViewController(currentViewController)
if (indexOfCurrentViewController == 0) || (indexOfCurrentViewController % 2 == 0) {
let nextViewController = self.modelController.pageViewController(self.pageViewController, viewControllerAfter: currentViewController)
viewControllers = [currentViewController, nextViewController!]
} else {
let previousViewController = self.modelController.pageViewController(self.pageViewController, viewControllerBefore: currentViewController)
viewControllers = [previousViewController!, currentViewController]
}
self.pageViewController.setViewControllers(viewControllers, direction: .forward, animated: true, completion: {done in })
return .mid
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment