Change VC Index in Page View Controller (Swift)

Using the following code, I have a series of view controllers built into the page view controller that I am viewing. I just can't seem to find a way to navigate to another view controller using a panel button click. I am planning to write a separate function for each panel button icon in each view controller.

class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    private var pages: [UIViewController]!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.dataSource = self
        self.delegate = self

        self.pages = [
            self.storyboard!.instantiateViewControllerWithIdentifier("FirstNav") as! UINavigationController,
            self.storyboard!.instantiateViewControllerWithIdentifier("SecondNav") as! UINavigationController,
            self.storyboard!.instantiateViewControllerWithIdentifier("ThirdNav") as! UINavigationController,
            self.storyboard!.instantiateViewControllerWithIdentifier("FourthNav") as! UINavigationController
        ]

        let startingViewController = self.pages.first! as UIViewController
        self.setViewControllers([startingViewController], direction: .Forward, animated: false, completion: nil)
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        let index = (self.pages as NSArray).indexOfObject(viewController)

        // if currently displaying last view controller, return nil to indicate that there is no next view controller
        return (index == self.pages.count - 1 ? nil : self.pages[index + 1])
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        let index = (self.pages as NSArray).indexOfObject(viewController)

        // if currently displaying first view controller, return nil to indicate that there is no previous view controller
        return (index == 0 ? nil : self.pages[index - 1])
    }

}

      

+3


source to share


2 answers


Change the implementation PageViewController

to the following (I made some changes to the already implemented methods and added a new instance method.)

class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    private var pages: [UINavigationController]!

    private var currentPageIndex: Int!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.dataSource = self
        self.delegate = self

        self.pages = [
            self.storyboard!.instantiateViewControllerWithIdentifier("FirstNav") as! UINavigationController,
            self.storyboard!.instantiateViewControllerWithIdentifier("SecondNav") as! UINavigationController,
            self.storyboard!.instantiateViewControllerWithIdentifier("ThirdNav") as! UINavigationController,
            self.storyboard!.instantiateViewControllerWithIdentifier("FourthNav") as! UINavigationController
        ]

        (self.pages[0].topViewController as! FirstViewController).parentPageViewController = self
        (self.pages[1].topViewController as! SecondViewController).parentPageViewController = self
        (self.pages[2].topViewController as! ThirdViewController).parentPageViewController = self
        (self.pages[3].topViewController as! FourthViewController).parentPageViewController = self

        self.currentPageIndex = 0
        let startingViewController = self.pages.first! as UINavigationController
        self.setViewControllers([startingViewController], direction: .Forward, animated: false, completion: nil)
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        let index = (self.pages as NSArray).indexOfObject(viewController)
        self.currentPageIndex = index

        // if currently displaying last view controller, return nil to indicate that there is no next view controller
        return (self.currentPageIndex == self.pages.count - 1 ? nil : self.pages[self.currentPageIndex + 1])
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        let index = (self.pages as NSArray).indexOfObject(viewController)
        self.currentPageIndex = index

        // if currently displaying first view controller, return nil to indicate that there is no previous view controller
        return (index == 0 ? nil : self.pages[index - 1])
    }



    func displayPageForIndex(index: Int, animated: Bool = true) {
        assert(index >= 0 && index < self.pages.count, "Error: Attempting to display a page for an out of bounds index")

        // nop if index == self.currentPageIndex
        if self.currentPageIndex == index { return }

        if index < self.currentPageIndex {
            self.setViewControllers([self.pages[index]], direction: .Reverse, animated: true, completion: nil)
        } else if index > self.currentPageIndex {
            self.setViewControllers([self.pages[index]], direction: .Forward, animated: true, completion: nil)
        }

        self.currentPageIndex = index
    }

}

      



Now, in each of your child controllers, add two pieces of code:

  • A property that maintains a weak reference to the parent instance PageViewController

    .

    weak var parentPageViewController: PageViewController!
    
          

  • An IBAction

    to which you connect each of the panel items. You may need to change the body of this method depending on how your storyboard is set up.

    @IBAction func barButtonTapped(sender: UIBarButtonItem) {
    
        var newIndex = -1
    
        switch sender.title! {
        case "First":
            newIndex = 0
        case "Second":
            newIndex = 1
        case "Third":
            newIndex = 2
        case "Fourth":
            newIndex = 3
        default: break
        }
    
        self.parentPageViewController.displayPageForIndex(newIndex)
    }
    
          

+2


source


Does every controller need to be embedded in UINavigationController

? You can just add UINavigationController

one UIViewController

this view controller is referenced by pageviewcontroller

and barButtonItem

when the tag barButtonItem

fires an action that tells the pageviewcontroller

indexes to change.



Or if you want to go with your current roadmap, which is barButtonItem

in each UINavigationController

, write a protocol with a delegate method didSelectBarButtonAtIndex

or whatever, then give each UINavigationController

a delegate property, pageviewcontroller

conform to the protocol, and become a delegate for each nav controller. Then, when the bar button is clicked, call the delegate method, which should cause the page control block to change its index.

0


source







All Articles