Page View Controller Tutorial With Page Dots
This post will cover setting up a UIPageViewController in Swift, and also adding the dots down the bottom to indicate what page the user is currently on. To get started create a new single view application.
The following animations shows the end result:
Setting up the Page View Controller
First of all head over to the Main.storyboard and set it up as follows:
To do this you will need to do the following:
- Drag a Page View Controller from the Object Library above the default View Controller
- Drag the arrow to the Page View Controller, this will set it as the one that loads by default
- Drag a View Controller to the right of the default View Controller
- Set one of the View Controller background colors to red, and the other one to blue
Now we have this setup select the Red View Controller, and in the identity inspector in the top right set the storyboard id to sbRed
Do the same thing for the Blue View Controller, this time naming it sbBlue
Then select the Page View Controller, in the attributes inspector in the top right change the Transition Style to Scroll.
Now we have this setup it’s time to add a new page controller class and code it.
Go File->New->File, select Cocoa Touch Class. Name it PageViewController and change the Subclass of to UIPageController
Go next, and create our class. Then go back to the storyboard, select the page view controller and in the identity inspector in the top right set it’s class to the PageViewController we just created.
Now open up PageViewController and lets code it!
First of all ad UIPageViewControllerDelegate and UIPageViewControllerData source to our class as follows:
import UIKit class PageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {
Then we add the following function, this is used to load the view controllers as you scroll through the different views.
func newVc(viewController: String) -> UIViewController { return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: viewController) }
Now above view did load add the following, the orderedViewControllers holds an array of View Controllers. If you want to add another View Controller to your page controller, this is the place to add it. We are adding in them by the storyboard identifiers sbBlue and sbRed we added earlier.
lazy var orderedViewControllers: [UIViewController] = { return [self.newVc(viewController: "sbBlue"), self.newVc(viewController: "sbRed")] }()
Now add the following functions. These are used when your swiping through the page view controllers to load up the next view controller. This is configured so when you get to the last one, it will loop back to the start. If you swipe left on the first one it will load up the last one.
If you don’t want it to loop simply follow the instructions in the code to uncomment return nil and removing two lines of code. This is included in the code below.
// MARK: Data source functions. func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { guard let viewControllerIndex = orderedViewControllers.index(of: viewController) else { return nil } let previousIndex = viewControllerIndex - 1 // User is on the first view controller and swiped left to loop to // the last view controller. guard previousIndex >= 0 else { return orderedViewControllers.last // Uncommment the line below, remove the line above if you don't want the page control to loop. // return nil } guard orderedViewControllers.count > previousIndex else { return nil } return orderedViewControllers[previousIndex] } func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { guard let viewControllerIndex = orderedViewControllers.index(of: viewController) else { return nil } let nextIndex = viewControllerIndex + 1 let orderedViewControllersCount = orderedViewControllers.count // User is on the last view controller and swiped right to loop to // the first view controller. guard orderedViewControllersCount != nextIndex else { return orderedViewControllers.first // Uncommment the line below, remove the line above if you don't want the page control to loop. // return nil } guard orderedViewControllersCount > nextIndex else { return nil } return orderedViewControllers[nextIndex] }
Now in viewDidLoad() add the following:
self.dataSource = self // This sets up the first view that will show up on our page control if let firstViewController = orderedViewControllers.first { setViewControllers([firstViewController], direction: .forward, animated: true, completion: nil) }
Now run the app and you can scroll through the view controller pages!
Adding the page dot indicators
To add the page dot indications add a pageControl as follows above the viewDidLoad()
var pageControl = UIPageControl()
Now add the following function. This will position the page control at the bottom of the screen. The current page indication will be black, and the rest of the indicators will be white. You can change these to suit the design of your app.
func configurePageControl() { // The total number of pages that are available is based on how many available colors we have. pageControl = UIPageControl(frame: CGRect(x: 0,y: UIScreen.main.bounds.maxY - 50,width: UIScreen.main.bounds.width,height: 50)) self.pageControl.numberOfPages = orderedViewControllers.count self.pageControl.currentPage = 0 self.pageControl.tintColor = UIColor.black self.pageControl.pageIndicatorTintColor = UIColor.white self.pageControl.currentPageIndicatorTintColor = UIColor.black self.view.addSubview(pageControl) }
Now in viewDidLoad() add these two lines:
self.delegate = self configurePageControl()
And add the following function, this will make sure the page control indicator changes to the correct page as you scroll through.
// MARK: Delegate functions func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { let pageContentViewController = pageViewController.viewControllers![0] self.pageControl.currentPage = orderedViewControllers.index(of: pageContentViewController)! }
Now run the app and you can see the page indicator as follows: