Search code examples
iosswiftuipagecontrol

Buttons to scroll horizontally ViewControllers with UIPageViewController in Swift


I have the PageViewController to ScrollViewController by Swipe gesture. It works, but I want to modify this and use the button to scroll.

The problem: There are three ViewControllers in Storyboard but I don't know how to call parent class PageViewController and ask to change the current view to the next one.

For example, ViewController1 button "nextView" -> ViewController2. In the case of call ViewController2 directly the PageViewController control can be broken. Is it correct?

What code should be for the UIButton of ViewController1?

PageViewController code:

class PageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {

    lazy var orderedVC: [UIViewController] = {
        return [self.newViewController(viewController: "ViewController1"),
                self.newViewController(viewController: "ViewController2"),
                self.newViewController(viewController: "ViewController3")]
    }()

    //Create the PageControl
    var pageControl = UIPageControl()
    func configurePageControl() {
        pageControl = UIPageControl(frame: CGRect(x: 0, y: UIScreen.main.bounds.maxY - 50, width: UIScreen.main.bounds.width, height: 50))
        ...
        self.view.addSubview(pageControl)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.dataSource = self
        if let firstViewController = orderedVC.first {
            setViewControllers([firstViewController],
                               direction: .forward,
                               animated: true,
                               completion: nil)
        }
        self.delegate = self
        configurePageControl()
    }

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

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

        //Get index from the the views list BEFORE
        guard let viewControllerIndex = orderedVC.firstIndex(of: viewController)   else {return nil}
        let previousIndex = viewControllerIndex - 1

        //Limitations of the index
        guard previousIndex >= 0    else {return nil}
        guard orderedVC.count > previousIndex  else {return nil}

        return orderedVC[previousIndex]
    }

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

        //Get index from the the views list AFTER
        guard let viewControllerIndex = orderedVC.firstIndex(of: viewController)   else {return nil}
        let nextIndex = viewControllerIndex + 1

        //Limitations of the index
        guard orderedVC.count != nextIndex else {return nil}
        guard orderedVC.count > nextIndex  else {return nil}

        return orderedVC[nextIndex]
    }

    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousVC: [UIViewController], transitionCompleted completed: Bool) {
        let pageContentViewController = pageViewController.viewControllers![0]
        self.pageControl.currentPage = orderedVC.firstIndex(of: pageContentViewController)!
    }
}

Solution

  • Can use a custom protocol and make your PageView controller the delegate for the view controllers.

    protocol PageViewDelegate {
        func previousPage()
        func nextPage()
    }
    
    class ViewController: UIViewController {
        var pageViewDelegate: PageViewDelegate?
        @IBAction func previousButtonTapped(_ sender: Any) {
            pageViewDelegate?.previousPage()
        }
        @IBAction func nextButtonTapped(_ sender: Any) {
            pageViewDelegate?.nextPage()
        }
    }
    
    class PageViewController: UIPageViewController, PageViewDelegate {
        override func viewDidLoad() {
            super.viewDidLoad()
            // After the viewControllers have been setup
            self.viewControllers?.forEach {
                if let controller = $0 as? ViewController {
                    controller.pageViewDelegate = self
                }
            }
        }
        func previousPage() {
            //show previous page
        }
        func nextPage() {
            //show next page
        }
    }
    

    Read more about protocols here.