3

Basically I'd like to move my PageViewController not only with swipe but also with buttons.

@IBAction func nextButtonAction(_ sender: Any){

}

My PageViewController looks like in this guide

What I have:

  • PageViewController
  • 3 Viewcontrollers

Sorry if it's a duplicate didn't found exactly same situation

tried to call UIPageViewControllerDataSource on each ViewController but didn't work also I think this is not the best approach

Edited: This is my PageViewController

class PageVC: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    lazy var VCarr: [UIViewController] = {

        return [self.VCInstance(name: "signUpVerification"),
        self.VCInstance(name: "signUpVerification1"),
        self.VCInstance(name: "signUpVerification2"),
        ]
    }()

    func VCInstance(name:String) -> UIViewController {
        return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier:name)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.dataSource = self
        self.delegate = self
        if let firsVC = VCarr.first {

            setViewControllers([firsVC], direction: .forward, animated: true, completion: nil)

        }
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = VCarr.index(of: viewController) else { return nil }
        let previousIndex = viewControllerIndex - 1
        guard previousIndex >= 0 else {
            return nil
        }
        return VCarr[previousIndex]
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = VCarr.index(of: viewController) else { return nil }
        let nextIndex = viewControllerIndex + 1
        guard nextIndex < VCarr.count else {
            return nil
        }
        return VCarr[nextIndex]
    }



}

extension PageVC {
    func goToNextPage(animated: Bool = true, completion: ((Bool) -> Void)? = nil) {
        if let currentViewController = VCarr.first {
            if let nextPage = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) //for some reasons there's nil {
                setViewControllers([nextPage], direction: .forward, animated: animated, completion: completion)
            }
        }
    }
}

this is Viewcontroller where I call it:

var pageVC = PageVC()
@IBAction func nextButtonAction(_ sender: Any){

   pageVC.goToNextPage()

}

Solution:

YourViewController: {
 @IBAction func nextButtonAction(_ sender: Any){
        let pageViewController = self.parent as! PageVC
        pageViewController.nextPageWithIndex(index: 1)


    }
}

PageViewController: {
   func nextPageWithIndex(index: Int) {
        setViewControllers([VCarr[index]], direction: .forward, animated: true, completion: nil)
    }
}
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Artyom
  • 371
  • 1
  • 4
  • 14
  • Checkout this question :- https://stackoverflow.com/questions/13633059/uipageviewcontroller-how-do-i-correctly-jump-to-a-specific-page-without-messing/18602186 – Leena Nov 30 '17 at 11:28
  • I find this Answer is the best, hope it help [see this link](https://stackoverflow.com/a/44691025/2510116) – Rooh Al-mahaba Oct 02 '18 at 13:38

2 Answers2

7

To move page viewController to by button click you can achieve very simply by using following extension

extension UIPageViewController {
    func goToNextPage(animated: Bool = true, completion: ((Bool) -> Void)? = nil) {
        if let currentViewController = viewControllers?[0] {
            if let nextPage = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) {
                setViewControllers([nextPage], direction: .forward, animated: animated, completion: completion)
            }
        }
    }

    func goToPreviousPage(animated: Bool = true, completion: ((Bool) -> Void)? = nil) {
        if let currentViewController = viewControllers?[0] {
            if let previousPage = dataSource?.pageViewController(self, viewControllerBefore: currentViewController){
                setViewControllers([previousPage], direction: .reverse, animated: true, completion: completion)
            }
        }
    }
}

To move forward

self.pageViewController.goToNextPage()

To move backward

self.pageViewController.goToPreviousPage()

don't forget to check whether the index available or not

for example:

if pageArray.count > currentIdex {
self.pageViewController.goToNextPage()
}

Hope this will help you

Ganesh Manickam
  • 2,113
  • 3
  • 20
  • 28
  • thank you for help but unfortunately I get an error. `index 0 beyond bounds for empty NSArray` – Artyom Nov 30 '17 at 12:08
  • did you get the crash while swipe next page or crash only happen when click on button? – Ganesh Manickam Nov 30 '17 at 16:21
  • if you mean swipe with gesture then no it works and it should be. Problem with the button `I get this error Unbalanced calls to begin/end appearance transitions` – Artyom Nov 30 '17 at 16:21
  • only with button – Artyom Nov 30 '17 at 16:24
  • Have you remove` extension PageVC { func goToNextPage(animated: Bool = true, completion: ((Bool) -> Void)? = nil) { if let currentViewController = VCarr.first { if let nextPage = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) //for some reasons there's nil { setViewControllers([nextPage], direction: .forward, animated: animated, completion: completion) } } } }` – Ganesh Manickam Nov 30 '17 at 18:44
  • yes I did just to see what it does. now my extension looks like this `extension PageVC { func goToNextPage(animated: Bool = true, completion: ((Bool) -> Void)? = nil) { self.dataSource = self if let currentViewController = VCarr.first { if let nextPage = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) { setViewControllers([nextPage], direction: .forward, animated: animated, completion: completion) } } } }` and i get this error `Unbalanced calls to begin/end appearance transitions for` – Artyom Nov 30 '17 at 18:57
  • use the extension which i post in answer that will solve this issue – Ganesh Manickam Dec 01 '17 at 05:08
  • 2
    I found this helpful. Thanks!. Save current index globally and need to use like viewControllers?[currentIndex]. Update currentIndex on UIPageViewController delegates accordingly. – Gurjinder Singh Jul 25 '19 at 13:40
0

Try adding this method in your button Action for moving from first View Controller to second:

self.pageViewController.setViewControllers([self.viewControllerAtIndex(1)!], direction: .forward, animated: true, completion: nil)
pageControl2.currentPage = 1

Rest you can add your current PageTracker using PageControl.

self.pageViewController.setViewControllers([self.viewControllerAtIndex(pageControl.currentPage + 1)!], direction: .forward, animated: true, completion: nil)
pageControl.currentPage += 1
Ravi Dhorajiya
  • 1,531
  • 3
  • 21
  • 26
Sucharu Hasija
  • 1,096
  • 11
  • 23