pageControl hidden when pageCurl forward

I have a simple setup.


A PageViewController, with ghorizontral navigation and Page Curl defined in IB


3 UIViewControllers, with storyboard ID as Page1, Page2, Page3

On each, just a label with the Page x content and a UIImageView with colored background


In PageViewController, I define a pageControl programmatically (could not find how to define in IB).


Then, as soon as I start swiping to turn from initial page (e.g., 1) to next page (e.g., 2), pageControl hides on initial page (1) and appears on the new page (2), with the old value (the one of page 1). Idem form 2 to 3.

However, when I swipe to return from a page (e.g., 2) to previous page (e.g., 1), pageControl remains visible on page 2, not visible on page 1 until turning page has completed.

Just as if during a transition, pageControl moved (with its present value) to the page beneath.

Is it intended behavior ? Why different for forward or reverse swipe ?


I tried setting

pageControl.defersCurrentPageDisplay = false

with no effect.


Here is the code for the PageViewController.


import UIKit

class PageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {

    let lightGray = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0)
   
    var pageControl = UIPageControl()

    func newVc(viewControllerID: String) -> UIViewController {
        return storyboard!.instantiateViewController(withIdentifier: viewControllerID)
    }
   
    lazy var orderedViewControllers: [UIViewController] = {
        return [self.newVc(viewControllerID: "Page1"),
                self.newVc(viewControllerID: "Page2"),
                self.newVc(viewControllerID: "Page3")]
    }()
   
    var currentlyShowingIndex = 0
   
    override func viewDidLoad() {
        super.viewDidLoad()

        let childControllers: [UIViewController] = [orderedViewControllers.first!]
       
        self.setViewControllers(childControllers, direction: .forward, animated: false, completion: nil)
       
        self.view.frame = self.view.bounds
       
        self.dataSource = self
        self.delegate = self
        configurePageControl()
    }
   

    func configurePageControl() {
       
        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 = lightGray // UIColor.gray
        self.pageControl.currentPageIndicatorTintColor = UIColor.green
          //        self.pageControl.defersCurrentPageDisplay = false     // This has no effect
        self.view.addSubview(pageControl)
    }
   
    // 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)!
        switch self.pageControl.currentPage {
        case 0: self.pageControl.currentPageIndicatorTintColor = .green
        case 1: self.pageControl.currentPageIndicatorTintColor = .orange
        case 2: self.pageControl.currentPageIndicatorTintColor = .red
        default: self.pageControl.currentPageIndicatorTintColor = lightGray // .gray
        }
       
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
       
        guard let viewControllerIndex = orderedViewControllers.index(of: viewController) else {
            return nil
        }
        let previousIndex = viewControllerIndex - 1
        guard previousIndex >= 0 else {
            return nil
        }
        guard orderedViewControllers.count > previousIndex else {
            return nil
        }
        currentlyShowingIndex -= 1
       
        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
        guard orderedViewControllersCount != nextIndex else {
            return nil
        }
        guard orderedViewControllersCount > nextIndex else {
            return nil
        }
        currentlyShowingIndex += 1
       
        return orderedViewControllers[nextIndex]
    }
   
    func viewController(at index: Int) -> UIViewController {
        return orderedViewControllers[index]
    }
   
    func presentationIndex(for pageViewController: UIPageViewController) -> Int {
        return currentlyShowingIndex
    }
   
    func presentationCount(for pageViewController: UIPageViewController) -> Int {
        return orderedViewControllers.count
    }

}

Replies

Is the scenario above the same regardless if the view is one page at a time or two (left & right)? Portrait vs. landscape on iPad, as an example.


I've used PVV in the past and don't recall this issue, but that was with older API & tools.


Control forward is hidden, I think, when no additional pages are available, so maybe the count in your example is off...


Reference:

/*
    Copyright (C) 2015 Apple Inc. All Rights Reserved.
    See LICENSE.txt for this sample’s licensing information
    
    Abstract:
    A view controller that demonstrates how to use `UIPageViewController`. Each page shows a `DataItem` via an instance of a `DataItemViewController`.
*/


import UIKit


class PageViewController: UIPageViewController, UIPageViewControllerDataSource {


    private let dataItems = DataItem.sampleItems.filter { $0.group == .Lola }
    
    private let dataItemViewControllerCache = NSCache()
    
    // MARK: UIViewController
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        dataSource = self
        
        let initialViewController = dataItemViewControllerForPage(0)
        setViewControllers([initialViewController], direction: .Forward, animated: false, completion: nil)
    }


    // MARK: UIPageViewControllerDataSource
    
    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        let index = indexOfDataItemForViewController(viewController)
        
        if index > 0 {
            return dataItemViewControllerForPage(index - 1)
        }
        else {
            return nil
        }
    }
    
    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        let index = indexOfDataItemForViewController(viewController)
        
        if index < dataItems.count - 1 {
            return dataItemViewControllerForPage(index + 1)
        }
        else {
            return nil
        }
    }
    
    func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
        return dataItems.count
    }


    func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
        guard let currentViewController = pageViewController.viewControllers?.first else { fatalError("Unable to get the page controller's current view controller.") }
        
        return indexOfDataItemForViewController(currentViewController)
    }
    
    // MARK: Convenience
    
    private func indexOfDataItemForViewController(viewController: UIViewController) -> Int {
        guard let viewController = viewController as? DataItemViewController else { fatalError("Unexpected view controller type in page view controller.") }
        guard let viewControllerIndex = dataItems.indexOf(viewController.dataItem) else { fatalError("View controller's data item not found.") }
        
        return viewControllerIndex
    }
    
    private func dataItemViewControllerForPage(pageIndex: Int) -> DataItemViewController {
        let dataItem = dataItems[pageIndex]
        
        if let cachedController = dataItemViewControllerCache.objectForKey(dataItem.identifier) as? DataItemViewController {
            // Return the cached view controller.
            return cachedController
        }
        else {
            // Instantiate and configure a `DataItemViewController` for the `DataItem`.
            guard let controller = storyboard?.instantiateViewControllerWithIdentifier(DataItemViewController.storyboardIdentifier) as? DataItemViewController else { fatalError("Unable to instantiate a DataItemViewController.") }
            controller.configureWithDataItem(dataItem)
            
            // Cache the view controller so it can be reused.
            dataItemViewControllerCache.setObject(controller, forKey: dataItem.identifier)
            
            // Return the newly created and cached view controller.
            return controller
        }
    }
}