Using NSPageController

One type of controller you can add to a macOS project storyboard is a page controller. The main purpose of the page controller is to display the contents of two or more view controllers that users can swipe left and right like swiping through pages in an e-book.

To use a page controller, you need to add a page controller to a storyboard. Next, you need to create additional view controllers that are completely separate from the storyboard (not connected to any existing storyboard scenes through segues). These view controllers will only appear within the page controller. You must then give each of these view controllers a unique identifier (name).

To create a unique identifier for each view controller, click on that view controller and then choose View > Utilities > Show Identity Inspector to open the Identity Inspector for that view controller.

Click the blue icon in the top, middle of the view controller window. Then click in the Storyboard ID text field in the Identity Inspector pane and type a descriptive name.

This name can be anything you ant but you’ll refer to this descriptive name later when making the view controller appear inside the page controller.

Next, you must create a Swift class file for your page controller. To do this you’ll need to create a new class file and make sure its subclass is NSPageController. The name can be arbitrary but you’ll need to remember this name when connecting it to the page controller in the storyboard.

Now click on the page controller in your storyboard, click on the blue icon in the top, middle of the Page Controller, and choose View > Utilities > Show Identity Inspector. The Identity Inspector pane appears. Click in the Class popup menu and choose the name you created for the page controller class file.

At this point, you’ve created a page controller and two or more view controllers that are separate from he rest of your storyboard. Now you’ll need to start writing Swift code.

Start by defining your page controller Swift file as an NSPageControllerDelegate. So if you named your Swift class file to control the page control as MyPageController, you’ll need to edit this file so the class heading looks like this:

class MyPageController: NSPageController, NSPageControllerDelegate {

Underneath this class file heading, create an array. The number of items in this array must be equal to the number of view controllers you want to display inside the page controller. So if you wanted to display three view controllers in the page controller, you might create an array with three arbitrarily named items like this:

var myViewArray = ["one", "two", "three"]

Inside the viewDidLoad function, you need to define the class file as its own delegate, set the arrangedObjects property to the name of your array, and define a transitionStyle as either:

  • .horizontalStrip
  • .stackBook
  • .stackHistory
    override func viewDidLoad() {
        super.viewDidLoad()

        delegate = self
        self.arrangedObjects = myViewArray
        self.transitionStyle = .horizontalStrip
    }

The transitionStyle property defines how the page controller displays the view controllers.

Now you need to add three additional functions to this page controller Swift class file:

   func pageController(_ pageController: NSPageController, viewControllerForIdentifier identifier: String) -> NSViewController {
        
        switch identifier {
        case "one":
            return NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "Page01") as! NSViewController
        case "two":
            return NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "Page02") as! NSViewController
        case "three":
            return NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "Page03") as! NSViewController
        default:
            return self.storyboard?.instantiateController(withIdentifier: identifier) as! NSViewController
        }
    }
    
    func pageController(_ pageController: NSPageController, identifierFor object: Any) -> String {
        return String(describing: object)
        
    }
    
    func pageControllerDidEndLiveTransition(_ pageController: NSPageController) {
        self.completeTransition()
    }

The first function uses a switch statement that uses the strings (“one”, “two”, and “three”) that are stored in the array, which is stored in the page controller’s arrangedObjects property. This switch statement links each array item to a specific view controller in the storyboard.

Remember, these three view controllers are not connected to any part of the storyboard but can be retrieved using their Storyboard ID.

The second function displays the view controller in the page controller.

The third function ends the transition when the user swipes left or right.

The complete page controller Swift class file contents should look like this:

import Cocoa

class MyPageController: NSPageController, NSPageControllerDelegate {
    
    var myViewArray = ["one", "two", "three"]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
        delegate = self
        self.arrangedObjects = myViewArray
        self.transitionStyle = .stackBook
    }
    
    func pageController(_ pageController: NSPageController, viewControllerForIdentifier identifier: String) -> NSViewController {
        
        switch identifier {
        case "one":
            return NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "Page01") as! NSViewController
        case "two":
            return NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "Page02") as! NSViewController
        case "three":
            return NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "Page03") as! NSViewController
        default:
            return self.storyboard?.instantiateController(withIdentifier: identifier) as! NSViewController
        }
    }
    
    func pageController(_ pageController: NSPageController, identifierFor object: Any) -> String {
        return String(describing: object)
        
    }
    
    func pageControllerDidEndLiveTransition(_ pageController: NSPageController) {
        self.completeTransition()
    }
    
}
Sample NSPageController example
March 26th, 2017 by
HTML Snippets Powered By : XYZScripts.com