2

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?

Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
CristianMoisei
  • 2,071
  • 2
  • 22
  • 28
  • Cristian, before I fully review your question. It's possible **this can help** It's the full tutorial on container views from a handsome list member! https://stackoverflow.com/a/23403979/294884 Please note in particular the critical section "How to connect 'to' the child controller..." (near the middle) – Fattie Mar 16 '19 at 17:17

1 Answers1

1

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){
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • Thanks, but I tried that and I get: Value of type 'PageController' has no member 'advancePage' – CristianMoisei Mar 16 '19 at 15:55
  • Edit: I'm an idiot, I pressed undo too many times and reverted back to UIPageViewController. instead of self. – CristianMoisei Mar 16 '19 at 16:03
  • 1
    it's `#selector(self.advancePage)` not `#selector(UIPageViewController.advancePage())` – Shehata Gamal Mar 16 '19 at 16:05
  • This worked, thanks. Pressing the button, crashes the app with this error: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'The number of view controllers provided (3) doesn't match the number required (1) for the requested transition' so I suppose there's something wrong with my function? – CristianMoisei Mar 16 '19 at 16:14
  • I found and solved the problem with your help, thanks again. I'll update the question for others to have it too and select your answer as the answer. – CristianMoisei Mar 16 '19 at 16:26
  • instead of `pages` supply `pages[nextIndex]` where `nextIndex` is the index to be shown – Shehata Gamal Mar 16 '19 at 16:26
  • Don't edit the answer into the question -- update this answer to reflect what you established in the comments etc., or write a new answer. – Caleb Mar 16 '19 at 16:27
  • 1
    That's ok, the fix is what you suggested so the info is all here. – CristianMoisei Mar 16 '19 at 16:27
  • @Sh_Khan, I'm sorry to bother you again, but would you know how to get the Page Control (dots) to work with this setup? All the answers I find are saying it should work automatically for as long as I provide the presentationIndex and presentationCount functions (which I am), but I don't think those work if I want the dots to be on the parent ViewController. – CristianMoisei Mar 16 '19 at 17:04
  • see here https://samwize.com/2016/03/08/using-uipageviewcontroller-with-custom-uipagecontrol/ but make sure to use updated swift 3 method signature – Shehata Gamal Mar 16 '19 at 17:47