PageViewController current page index in Swift

52,057

Solution 1

You can use didFinishAnimating, and set tags to viewcontrollers. try this

func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool)
{
   if (!completed)
  {
    return
  }
  self.pageControl.currentPageIndex = pageViewController.viewControllers!.first!.view.tag //Page Index
}

Solution 2

Add this code to your UIPageViewController.

var pages = [UIViewController]()
var currentIndex: Int {
    guard let vc = viewControllers?.first else { return 0 }
    return pages.firstIndex(of: vc) ?? 0
}

Solution 3

In Swift 3

Override didFinishAnimating function of UIPageViewControllerDelegate like this:

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    if completed {
        if let currentViewController = pageViewController.viewControllers![0] as? WalkthroughContentViewController {
            pageControl.currentPage = currentViewController.index
        }
    }
}

where WalkthroughContentViewController is the UIViewController presented by UIPageViewController

Remember to keep an index variable inside the WalkthroughContentViewController. Also, in the viewDidLoad method set:

delegate = self

Solution 4

Swift 3: full programmatic PageViewController example to get/set the current page index without view tagging:

enum PageViewType:String {
        case green = "greenView"
        case blue = "blueView"
        case red = "redView"  
}

class MyPageViewController: UIPageViewController {

    private (set) lazy var orderedViewControllers:[UIViewController] = {
         return [self.newPageView(.green),
                self.newPageView(.blue),
                self.newPageView(.red)
        ]
    }

    var currentIndex:Int {
            get {
                return orderedViewControllers.index(of: self.viewControllers!.first!)!
            }

            set {
                guard newValue >= 0,
                    newValue < orderedViewControllers.count else {
                    return
                }

                let vc = orderedViewControllers[newValue]
                let direction:UIPageViewControllerNavigationDirection = newValue > currentIndex ? .forward : .reverse            
                self.setViewControllers([vc], direction: direction, animated: true, completion: nil) 
            }
        }

    override func viewDidLoad() {
        super.viewDidLoad()

        dataSource = self

        if let firstViewController = orderedViewControllers.first {
            setViewControllers([firstViewController],
                           direction: .forward,
                           animated: true,
                           completion: nil)
        }
    }

    private func newPageView(_ viewType:PageViewType) -> UIViewController {
        let vc = self.storyboard?.instantiateViewController(withIdentifier: viewType.rawValue)       
        return vc
    }
}

UIPageViewController DataSource implementation:

extension MyPageViewController:UIPageViewControllerDataSource {

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

        let previousIndex = currentIndex - 1

        guard previousIndex >= 0 else {
            return nil
        }

        guard orderedViewControllers.count > previousIndex else {
            return nil
        }

        return orderedViewControllers[previousIndex]   
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {         
        let nextIndex = currentIndex + 1

        guard orderedViewControllers.count != nextIndex else {
            return nil
        }

        guard orderedViewControllers.count > nextIndex else {
            return nil
        }

        return orderedViewControllers[nextIndex]
    }

    func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
        return orderedViewControllers.count
    }

    func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {

        return currentIndex
    }
}

Solution 5

First, have your UIPageViewController implement the UIPageViewControllerDataSource method presentationIndex(for pageViewController: UIPageViewController) -> Int to return the index for each of the PageViewController's ViewControllers.

Then in your delegate, access the datasource through the passed-in PageViewController:

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    guard let dataSource = pageViewController.dataSource, 
          let currentIndex = dataSource.presentationIndex?(for: pageViewController) else { preconditionFailure() }

}
Share:
52,057
LeNI
Author by

LeNI

Updated on March 07, 2020

Comments

  • LeNI
    LeNI about 4 years

    I want to get current index of a pageViewController, I don't know how I get the visible pages index.

    func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool,previousViewControllers: [UIViewController],transitionCompleted completed: Bool)
    {
        // How to get it?
    
    }
    
  • David Seek
    David Seek over 7 years
    but pageViewController.viewControllers!.first!.view.tag is always 0 because it's always first :(
  • Mahesh Narla
    Mahesh Narla over 7 years
    Getting error Value of type 'UIPageVieController' has no member 'currentPage'
  • Pierre Perrin
    Pierre Perrin almost 7 years
    Yes David Seek, you could use the func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool)
  • rajesh
    rajesh over 6 years
    how to call currentIndex function in viecontroller
  • FrothSturgeon
    FrothSturgeon over 4 years
    This comes across as a hack. Use of UIView tags and explicitly unwrapped optionals are both bad practices. Not only is there a performance overhead -- tags are implemented with objc_get/setAssociatedObject() which requires a dictionary lookup for each get or set -- but there's always a way to accomplish what's done with a tag some other way.
  • Fattie
    Fattie almost 4 years
    THIS IS NOW DEAD EASY scroll down to @igor 's answer. For anyone googling here DON'T use this very out of date answer.
  • Igor
    Igor over 3 years
    In implementation of class UIPageViewController.
  • karthikeyan
    karthikeyan over 3 years
    your code crashing if i swipe left or right .... Fatal error: Unexpectedly found nil while unwrapping an Optional
  • Sheshnath
    Sheshnath about 2 years