Swift UIPageView - 如何获取 PageControll 的索引?

Swift UIPageView - how to get the index for PageControll?

我正在尝试让 pageControl 指标点工作,但我无法找到如何让当前 viewController 将 pageControl.currentPage 设置为正确的索引。

我是这样设置的 UIPageController:

class PageViewController: UIPageViewController, UIPageViewControllerDataSource {

var pageControl = UIPageControl()

lazy var viewControllerList: [UIViewController] = {

    let sb = UIStoryboard(name: "Main", bundle: nil)

    let vc1 = sb.instantiateViewController(withIdentifier: "VC1")
    let vc2 = sb.instantiateViewController(withIdentifier: "VC2")
    let vc3 = sb.instantiateViewController(withIdentifier: "VC3")

    return [vc1, vc2, vc3]
}()

override func viewDidLoad() {
    super.viewDidLoad()

    //  seting up the dots
    pageControl.frame = CGRect(x: view.frame.midX - 50, y: view.frame.maxY - 80, width: 100, height: 100)
    pageControl.numberOfPages = 3
    pageControl.currentPage = 0
    view.addSubview(pageControl)
    view.bringSubview(toFront: pageControl)


    self.dataSource = self

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

func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
    guard let viewControllerIndex = viewControllerList.index(of: viewController) else {return nil}

    let prevIndex = viewControllerIndex - 1
    guard prevIndex >= 0 else {return nil}
    guard viewControllerList.count > prevIndex else {return nil}

    return viewControllerList[prevIndex]

}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
    guard let viewControllerIndex = viewControllerList.index(of: viewController) else {return nil}

    let nextIndex = viewControllerIndex + 1
    guard viewControllerList.count != nextIndex else {return nil}
    guard viewControllerList.count > nextIndex else {return nil}

    return viewControllerList[nextIndex]
}
}

我在这里尝试了几个答案,但 none 似乎适用于我的情况。如何找出当前索引是什么以将 pageControl.currentPage 设置为正确的索引(我想我必须在两个函数 viewControllerBeforeviewControllerAfter 中设置它?

我尝试使用 viewControllerIndex(previewIndex 或 nextIndex),但这会让点指示器从第一个点跳到第三个点(不是随机的,但也不是有序的)。

UIPageViewController 有一个内置的页面指示器,如果实现了所需的 UIPageViewControllerDataSource 方法,该指示器就会出现。来自文档:

If both of the methods in Supporting a Page Indicator are implemented and the page view controller’s transition style is scroll, a page indicator is visible.

所需的方法是:

public func presentationCount(for pageViewController: UIPageViewController) -> Int
public func presentationIndex(for pageViewController: UIPageViewController) -> Int

但您的示例使用自定义 UIPageControl 而不是内置页面指示器。这种方法提供了更大的灵活性。例如,虽然内置控件始终位于视图底部,但您可以轻松地将自定义控件置于视图顶部。

要将自定义 UIPageControl 连接到 UIPageViewController,您必须实施 UIPageViewControllerDelegate。这允许设置 pageControl.currentPage 以响应滑动手势。为此:

将成员添加到您的class:

var pendingPage: Int?

设置委托:

override func viewDidLoad() {
    ...
    self.delegate = self
    ...
}

并实现委托协议的一些方法。我更喜欢为每个协议添加一个扩展,以便协议名称及其实现明确分组。

extension PageViewController: UIPageViewControllerDelegate { 
    // Sent when a gesture-initiated transition begins.
    func pageViewController(_ pageViewController: UIPageViewController,
                            willTransitionTo pendingViewControllers: [UIViewController]) {
        pendingPage = viewControllerList.index(of: pendingViewControllers.first!)
    }

    // Sent when a gesture-initiated transition ends. The 'finished' parameter indicates whether the animation finished,
    // while the 'completed' parameter indicates whether the transition completed or bailed out (if the user let go early).
    func pageViewController(_ pageViewController: UIPageViewController,
                            didFinishAnimating finished: Bool,
                            previousViewControllers: [UIViewController],
                            transitionCompleted completed: Bool) {
        guard completed, let page = pendingPage else {
            return
        }
        pageControl.currentPage = page
    }
}

我使用了 msmolens 答案,但没有使用扩展名:

    class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    var pageControl = UIPageControl()

    lazy var viewControllerList: [UIViewController] = {

        let sb = UIStoryboard(name: "Main", bundle: nil)

        let vc1 = sb.instantiateViewController(withIdentifier: "VC1")
        let vc2 = sb.instantiateViewController(withIdentifier: "VC2")
        let vc3 = sb.instantiateViewController(withIdentifier: "VC3")

        return [vc1, vc2, vc3]
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.delegate = self

        //  seting up the dots

        pageControl.frame = CGRect(x: view.frame.midX - 50, y: view.frame.maxY - 80, width: 100, height: 100)
        pageControl.numberOfPages = 3
        pageControl.currentPage = 0
        view.addSubview(pageControl)
        view.bringSubview(toFront: pageControl)


        self.dataSource = self

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

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = viewControllerList.index(of: viewController) else {return nil}

        let prevIndex = viewControllerIndex - 1
        guard prevIndex >= 0 else {return nil}
        guard viewControllerList.count > prevIndex else {return nil}

        return viewControllerList[prevIndex]

    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = viewControllerList.index(of: viewController) else {return nil}

        let nextIndex = viewControllerIndex + 1
        guard viewControllerList.count != nextIndex else {return nil}
        guard viewControllerList.count > nextIndex else {return nil}

        return viewControllerList[nextIndex]
    }

     // Sent when a gesture-initiated transition begins.

    func pageViewController(_ pageViewController: UIPageViewController,
                            willTransitionTo pendingViewControllers: [UIViewController]) {
        pendingPage = viewControllerList.index(of: pendingViewControllers.first!)
    }

    // Sent when a gesture-initiated transition ends. The 'finished' parameter indicates whether the animation finished,
    // while the 'completed' parameter indicates whether the transition completed or bailed out (if the user let go early).

    func pageViewController(_ pageViewController: UIPageViewController,
                            didFinishAnimating finished: Bool,
                            previousViewControllers: [UIViewController],
                            transitionCompleted completed: Bool) {
        guard completed, let page = pendingPage else {
            return
        }
        pageControl.currentPage = page
        }
    }