read

I have previously provided 2 posts about UIPageViewController, but that’s not enough.

A very common problem with UIPageViewController is that you cannot customize the UIPageControl.

Or should I say, it is not straight forward.

The Trick

The trick is to use a custom UIPageControl.

You can drag one to your storyboard, link to your view controller. You will see this as pageControl in WalkthroughViewController below.

As you can infer from the view controller class name, an app walkthrough is a very good example where you want to have pages of tutorials.

In this implementation, I will also subclass my view controller with UIViewController (NOT UIPageViewController).

Therefore, I will create the UIPageViewController in code.

The Code

class WalkthroughViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    // The custom UIPageControl
    @IBOutlet weak var pageControl: UIPageControl!

    // The UIPageViewController
    var pageContainer: UIPageViewController!

    // The pages it contains
    var pages = [UIViewController]()

    // Track the current index
    var currentIndex: Int?
    private var pendingIndex: Int?

    // MARK: -

    override func viewDidLoad() {
        super.viewDidLoad()

        // Setup the pages
        let storyboard = UIStoryboard(name: "Walkthrough", bundle: nil)
        let page1: UIViewController! = storyboard.instantiateViewControllerWithIdentifier("page1")
        let page2: UIViewController! = storyboard.instantiateViewControllerWithIdentifier("page2")
        let page3: UIViewController! = storyboard.instantiateViewControllerWithIdentifier("page3")
        pages.append(page1)
        pages.append(page2)
        pages.append(page3)

        // Create the page container
        pageContainer = UIPageViewController(transitionStyle: .Scroll, navigationOrientation: .Horizontal, options: nil)
        pageContainer.delegate = self
        pageContainer.dataSource = self
        pageContainer.setViewControllers([page1], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)

        // Add it to the view
        view.addSubview(pageContainer.view)

        // Configure our custom pageControl
        view.bringSubviewToFront(pageControl)
        pageControl.numberOfPages = pages.count
        pageControl.currentPage = 0
    }

    // MARK: - UIPageViewController delegates

    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        let currentIndex = pages.indexOf(viewController)!
        if currentIndex == 0 {
            return nil
        }
        let previousIndex = abs((currentIndex - 1) % pages.count)
        return pages[previousIndex]
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        let currentIndex = pages.indexOf(viewController)!
        if currentIndex == pages.count-1 {
            return nil
        }
        let nextIndex = abs((currentIndex + 1) % pages.count)
        return pages[nextIndex]
    }

    func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [UIViewController]) {
        pendingIndex = pages.indexOf(pendingViewControllers.first!)
    }

    func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        if completed {
            currentIndex = pendingIndex
            if let index = currentIndex {
                pageControl.currentPage = index
            }
        }
    }
}

The Code to Remove

As important, you have to remove/comment these 2 methods, so that the default UIPageControl from the UIPageViewController is not shown.

//    func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
//        return pages.count
//    }
//    
//    func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
//        return 0
//    }

Image

@samwize

¯\_(ツ)_/¯

Back to Home