Skip to content

UIPageViewController

Overview

UIPageViewController is a class in iOS's UIKit framework that provides a way to implement a page-based navigation interface. It allows users to navigate between view controllers using gestures like swiping or tapping, commonly seen in apps like iBooks or onboarding screens.

Key Features

  • Page Navigation: Supports horizontal or vertical scrolling between view controllers.
  • Transition Styles: Offers two styles:
    • Page Curl: Mimics the effect of turning a page in a book.
    • Scroll: A continuous scrolling effect.
  • Spine Location: For page curl, defines where the "spine" of the book is (e.g., left, right, or middle for double-sided layouts).
  • Data Source and Delegate: Protocols to manage content and respond to user interactions.
  • Gesture-Based Navigation: Built-in support for swipe gestures to navigate pages.

Setting Up UIPageViewController

  1. Create a UIPageViewController: Initialize with a transition style and navigation orientation.

    swift
    let pageViewController = UIPageViewController(
        transitionStyle: .scroll,
        navigationOrientation: .horizontal,
        options: nil
    )
  2. Set Data Source and Delegate: Assign a data source to provide view controllers and a delegate to handle events.

    swift
    pageViewController.dataSource = self
    pageViewController.delegate = self
  3. Provide View Controllers: Implement the UIPageViewControllerDataSource protocol to supply view controllers for each page.

    swift
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        // Return the previous view controller or nil if none
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        // Return the next view controller or nil if none
    }
  4. Set Initial View Controller: Set the starting view controller using setViewControllers.

    swift
    pageViewController.setViewControllers([initialViewController], direction: .forward, animated: true, completion: nil)
  5. Add to View Hierarchy: Add the UIPageViewController to your view controller hierarchy.

    swift
    addChild(pageViewController)
    view.addSubview(pageViewController.view)
    pageViewController.didMove(toParent: self)

Example Implementation

Here’s a simple example of setting up a UIPageViewController with three content view controllers.

swift
class PageViewController: UIPageViewController, UIPageViewControllerDataSource {
    private var pages = [UIViewController]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Initialize pages
        let page1 = UIViewController()
        page1.view.backgroundColor = .red
        let page2 = UIViewController()
        page2.view.backgroundColor = .green
        let page3 = UIViewController()
        page3.view.backgroundColor = .blue
        pages = [page1, page2, page3]
        
        // Configure page view controller
        dataSource = self
        setViewControllers([pages[0]], direction: .forward, animated: true, completion: nil)
    }
    
    // MARK: - UIPageViewControllerDataSource
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let currentIndex = pages.firstIndex(of: viewController), currentIndex > 0 else { return nil }
        return pages[currentIndex - 1]
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let currentIndex = pages.firstIndex(of: viewController), currentIndex < pages.count - 1 else { return nil }
        return pages[currentIndex + 1]
    }
}

Customizing Behavior

  • Page Indicators: For scroll style, use UIPageControl to show dots indicating the number of pages and current position. Access via the data source method:
    swift
    func presentationCount(for pageViewController: UIPageViewController) -> Int {
        return pages.count
    }
    
    func presentationIndex(for pageViewController: UIPageViewController) -> Int {
        guard let current = pageViewController.viewControllers?.first, let index = pages.firstIndex(of: current) else { return 0 }
        return index
    }
  • Delegate Methods: Use UIPageViewControllerDelegate to respond to transitions:
    swift
    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        if completed {
            // Handle transition completion
        }
    }

Tips and Best Practices

  • Memory Management: Load view controllers lazily to avoid memory issues, especially with many pages.
  • Orientation: Ensure the navigation orientation matches your app’s design (horizontal or vertical).
  • Accessibility: Add accessibility labels to content for better user experience.
  • Testing: Test navigation on various devices to ensure smooth transitions and gesture handling.

Common Use Cases

  • Onboarding screens with swipeable tutorials.
  • Image galleries or carousels.
  • E-book or magazine-style interfaces with page curl effects.

Limitations

  • Limited to one view controller visible at a time (except in double-sided page curl mode).
  • Gesture conflicts may occur if embedded in other gesture-driven containers like UIScrollView.
  • Page curl transition is less common in modern apps due to its skeuomorphic design.

For more details, refer to Apple’s UIPageViewController documentation.

Released under the MIT License.