I'm trying to utilize a UIPageViewController
in a Swift app with multiple view controllers. I have 2 view controllers on my storyboard (firstViewController
and secondViewController
) that are both embedded in their own navigation controllers. They have storyboard identifiers "FirstViewController
" and "SecondViewController
". I also have a page view controller on my storyboard with identifierPageView
controller and set the navigation to horizontal and transition style to scroll in the attributes inspector. FirstViewController
is the root view controller of the app
I want firstViewController
to be the first page of the page view controller so I have written its class like so:
import Foundation
import UIKit
class FirsttViewController: UITableViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
override func viewDidLoad() {
let pageViewController: PageViewController = self.storyboard.instantiateViewControllerWithIdentifier("PageViewController") as PageViewController
pageViewController.delegate = self
var viewControllers: [UIViewController] = [self]
pageViewController.setViewControllers(viewControllers, direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height)
self.addChildViewController(pageViewController)
self.view.addSubview(pageViewController.view)
pageViewController.didMoveToParentViewController(self)
}
func pageViewController(pageViewController: UIPageViewController!, viewControllerAfterViewController viewController: UIViewController!) -> UIViewController! {
let secondViewController: SecondViewController = self.storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as SecondViewController
return secondViewController
}
func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! {
return nil
}
func presentationCountForPageViewController(pageViewController: UIPageViewController!) -> Int {
return 2
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController!) -> Int {
return 0
}
}
the file for SecondViewController
looks like this:
import Foundation
import UIKit
class SecondViewController: UITableViewController, UIPageViewControllerDataSource {
func pageViewController(pageViewController: UIPageViewController!, viewControllerAfterViewController viewController: UIViewController!) -> UIViewController! {
return nil
}
func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! {
let firstViewController: FirstViewController = self.storyboard.instantiateViewControllerWithIdentifier("FirstViewController") as FirstViewController
return firstViewController
}
}
However, when I run my app it doesn't seem to have a page view controller. It just shows firstViewController
and that's it. No dots, no pages, etc. Anyone know whats wrong? I've found a couple of Objective-C tutorials but they all cover using one view controller for all the pages and have a root view controller that is not a page in the pageView
so they weren't too much help. I was hoping it was going to be like using a tabBarController
where you just click and drag to the view controllers but thats not the case unfortunately. like I said I've not worked with one of these before so I'm sort of lost.
following iiFreeman's suggestion, I subclassed UIPageViewController
and made it the root in my storyboard file. below is the subclass
import Foundation
import UIKit
class PageViewController: UIPageViewController {
override func viewDidLoad() {
let startingViewController = self.storyboard.instantiateViewControllerWithIdentifier("FirstViewController") as FirstViewController
self.dataSource = startingViewController
var viewControllers: [UIViewController] = [startingViewController]
self.setViewControllers(viewControllers, direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
}
}
However now the app just hangs on a black screen and eventually Xcode loses connection to the simulator. I'm not really sure what's up.
OK, I got it figured out. since I needed the page view controller to be the root and handle everything, I subclassed UIPageViewController
as iiFreeman suggested and conformed to the delegate and data source protocols. I then set up the controller in viewDidLoad
, and implemented the delegate and data source methods. I added a property store an array of storyboard identifiers as well as one to keep track of the current index of that array. I also added a helper method to return the correct view controller given an index. I didn't need anything in my other tableView
controller subclasses since my page view controller was handling everything. One thing I did realize is since my tableViewController
s were embedded in navigation controllers, my page view controller actually needed to show the navigation controllers, not the tableView
controllers. below is my implementation:
import Foundation
import UIKit
class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var index = 0
var identifiers: NSArray = ["FirstNavigationController", "SecondNavigationController"]
override func viewDidLoad() {
self.dataSource = self
self.delegate = self
let startingViewController = self.viewControllerAtIndex(self.index)
let viewControllers: NSArray = [startingViewController]
self.setViewControllers(viewControllers, direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
}
func viewControllerAtIndex(index: Int) -> UINavigationController! {
//first view controller = firstViewControllers navigation controller
if index == 0 {
return self.storyboard.instantiateViewControllerWithIdentifier("FirstNavigationController") as UINavigationController
}
//second view controller = secondViewController's navigation controller
if index == 1 {
return self.storyboard.instantiateViewControllerWithIdentifier("SecondNavigationController") as UINavigationController
}
return nil
}
func pageViewController(pageViewController: UIPageViewController!, viewControllerAfterViewController viewController: UIViewController!) -> UIViewController! {
let identifier = viewController.restorationIdentifier
let index = self.identifiers.indexOfObject(identifier)
//if the index is the end of the array, return nil since we dont want a view controller after the last one
if index == identifiers.count - 1 {
return nil
}
//increment the index to get the viewController after the current index
self.index = self.index + 1
return self.viewControllerAtIndex(self.index)
}
func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! {
let identifier = viewController.restorationIdentifier
let index = self.identifiers.indexOfObject(identifier)
//if the index is 0, return nil since we dont want a view controller before the first one
if index == 0 {
return nil
}
//decrement the index to get the viewController before the current one
self.index = self.index - 1
return self.viewControllerAtIndex(self.index)
}
func presentationCountForPageViewController(pageViewController: UIPageViewController!) -> Int {
return self.identifiers.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController!) -> Int {
return 0
}
}