Search code examples
iosswiftuipageviewcontrolleruicontainerview

Swift: How to programatically advance a UIPageViewController that is inside a Container View?


I have one ViewController that contains a button and two image views that I would like to stay permanently, and a PageViewController that swipes through three other ViewControllers, and this all works well, however what I can't figure out how to do is how to go to the next slide programatically when the button is pressed.

Here's what my PageController class looks like (based on Fattie's very helpful answer here: UIPageViewController and storyboard):

class PageController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {


var pages = [UIViewController]()

override func viewDidLoad() {
    super.viewDidLoad()

    self.delegate = self
    self.dataSource = self

    let p1: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "onboardingText01")
    let p2: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "onboardingText02")
    let p3: UIViewController! = storyboard?.instantiateViewController(withIdentifier: "onboardingText03")

    pages.append(p1)
    pages.append(p2)
    pages.append(p3)

    setViewControllers([p1], direction: UIPageViewController.NavigationDirection.forward, animated: false, completion: nil)

}


func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController)-> UIViewController? {

    let currentPage = pages.index(of: viewController)!

    // used to prevent the PageViewController from looping
    if currentPage == 0 { return nil }

    let prev = abs((currentPage - 1) % pages.count)
    return pages[prev]

}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController)-> UIViewController? {

    let currentPage = pages.index(of: viewController)!

    // used to prevent the PageViewController from looping
    if currentPage == (pages.count - 1) { return nil }

    let nxt = abs((currentPage + 1) % pages.count)
    return pages[nxt]
}

func presentationIndex(for pageViewController: UIPageViewController)-> Int {
    return pages.count
}

}

The button is then defined as an action in the ViewController holding all these (separate file).

I tried using a notification/observer but I get error

Type 'UIPageViewController' has no member 'advancePage'

with the selector (I'm not sure how to call the function).

Inside viewDidLoad:

NotificationCenter.default.addObserver(self, selector: #selector(UIPageViewController.advancePage()), name: advance, object: nil)

Inside the UIPageViewController Class

    func advancePage(){
        setViewControllers(pages,
                           direction: UIPageViewController.NavigationDirection.forward,
                           animated: true,
                           completion: nil)
    }

Any ideas?


Solution

  • You need to add this inside PageController 's viewDidLoad

    NotificationCenter.default.addObserver(self, selector: #selector(self.advancePage), name: advance, object: nil)
    

    @objc func advancePage(_ note:NSNotification){