Swift 中的 PageViewController 当前页面索引

Posted

技术标签:

【中文标题】Swift 中的 PageViewController 当前页面索引【英文标题】:PageViewController current page index in Swift 【发布时间】:2015-09-28 12:17:27 【问题描述】:

我想获取 pageViewController 的当前索引,我不知道如何获取可见页面索引。

func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool,previousViewControllers: [UIViewController],transitionCompleted completed: Bool)

    // How to get it?


【问题讨论】:

看到这个链接可能对你有帮助***.com/questions/8400870/… 提供的参数告诉你什么? 现在很容易向下滚动到@igor 的答案。 【参考方案1】:

您可以使用 didFinishAnimating,并为视图控制器设置标签。试试这个

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

【讨论】:

pageViewController.viewControllers!.first!.view.tag 总是0 因为它总是第一个:( 是的,David Seek,您可以使用func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 这被认为是一种黑客行为。使用 UIView 标记和显式展开的选项都是不好的做法。不仅存在性能开销——标签是使用objc_get/setAssociatedObject() 实现的,这需要对每个 get 或 set 进行字典查找——而且总有一种方法可以通过其他方式完成标签所做的事情。 现在很容易向下滚动到@igor 的答案。对于在这里使用谷歌搜索的任何人,不要使用这个非常过时的答案。 @igor 的回答链接***.com/a/60562632/3145189【参考方案2】:

将此代码添加到您的UIPageViewController

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

【讨论】:

在 UIPageViewController 类的实现中。【参考方案3】:

在 Swift 3 中

像这样重写 UIPageViewControllerDelegate 的 didFinishAnimating 函数:

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
        
    

其中 WalkthroughContentViewController 是 UIPageViewController 呈现的 UIViewController

记得在 WalkthroughContentViewController 中保留一个索引变量。另外,在 viewDidLoad 方法集中:

delegate = self

【讨论】:

【参考方案4】:

Swift 3: 完整的编程 PageViewController 示例,无需视图标记即可获取/设置当前页面索引:

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 数据源实现:

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
    

【讨论】:

如何在viecontroller中调用currentIndex函数 如果我向左或向右滑动,您的代码将崩溃.... 致命错误:在展开 Optional 时意外发现 nil【参考方案5】:

不要忘记设置 pageviewcontroller 的委托。

 func createPageViewController() 
    // Create page view controller
    pageViewController = storyboard?.instantiateViewController(withIdentifier: "PageViewController") as? UIPageViewController
    pageViewController?.delegate = self
    pageViewController?.dataSource = self

    let startingViewController: ChildViewController = viewControllerAtIndex(index: 0)!
    let viewControllers: Array = [startingViewController]
    pageViewController?.setViewControllers(viewControllers, direction: .forward, animated: true, completion: nil)

    self.addChildViewController(pageViewController!)
    self.view.frame = CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height)
    self.view.addSubview((pageViewController?.view)!)
    self.pageViewController?.didMove(toParentViewController: self)


func viewControllerAtIndex(index: Int) -> ChildViewController?   
    // return nil here, if there won't be any page in pageviewcontroller

    // Create a new view controller and pass suitable data.
    let pageContentViewController: ChildViewController = storyboard?.instantiateViewController(withIdentifier: "ChildViewController") as! ChildViewController

    pageContentViewController.pageIndex = index
    return pageContentViewController


//Also add viewControllerAfter and viewControllerBefore methods

func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) 
    self.pendingIndex = (pendingViewControllers.first as! ChildViewController).pageIndex


func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 
    if completed 
        self.currentIndex = self.pendingIndex!
        //Perform your task here
    

【讨论】:

【参考方案6】:

首先,让您的 UIPageViewController 实现 UIPageViewControllerDataSource 方法 presentationIndex(for pageViewController: UIPageViewController) -&gt; Int 以返回每个 PageViewController 的 ViewController 的索引。

然后在你的delegate中,通过传入的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() 


【讨论】:

【参考方案7】:

试试看。

func pageViewController(pageViewController: UIPageViewController,didFinishAnimating finished: Bool,previousViewControllers: [UIViewController],transitionCompleted completed: Bool)
guard completed else  return 

self.pageControl.currentPage = pageViewController.viewControllers!.first!.view.tag
    

【讨论】:

获取错误“UIPageVieController”类型的值没有成员“currentPage”【参考方案8】:

你可以使用下一个方法:

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 
    guard
        completed,
        let viewControllerIndex = tutorialViews.index(of: pageViewController.viewControllers!.first!) else
            return
        

    self.currentIndex = viewControllerIndex

tutorialViews 是一个页面数组 (ViewControllers)。 并像这样初始化 currentIndex

var currentIndex = 0 
    didSet 
        self.updateContentForPage(withIndex: currentIndex)
    

【讨论】:

【参考方案9】:

Swift 4 版本

使用这些协议(UIPageViewControllerDelegateUIPageViewControllerDataSource)扩展 ViewController 类并添加以下函数帮助我使我的页面控件正常工作。

class ViewController : UIPageViewControllerDelegate,UIPageViewControllerDataSource 

    func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) 
        if let viewController = pendingViewControllers[0] as? DataViewController 
            self.lastPendingViewControllerIndex = viewController.index!
        
    

    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 
        if completed 
            pageControl.currentPage = self.lastPendingViewControllerIndex
            if lastPendingViewControllerIndex == 4 
                self.getstartedButton.isHidden=false
             else 
                self.getstartedButton.isHidden=true
            
        
    

【讨论】:

【参考方案10】:

在例如类 -> WalkthroughPageViewController) 中创建一个方法,这样:

 /* The method takes in a page index and creates the next content view controller. If the controller can
 be created, we call the built-in setViewControllers method and navigate to the next view controller.*/
func forward(index: Int) 
    if let nextViewController = contentViewController(at: index + 1) 
        setViewControllers([nextViewController], direction: .forward, animated: true, completion: nil)
    

在控制所述 UIPageController 的类中,这将是一个控制器视图(类 -> WalkthroughContentViewController),其中包含一个以下按钮,该按钮传递到下一页并更新属性“pageControl.currentPage”(它本身就是UIpageControl),实现:

class WalkthroughContentViewController: UIViewController 

@IBOutlet var headingLabel: UILabel!
@IBOutlet var contentLabel: UILabel!
@IBOutlet var forwardButton: UIButton!
@IBOutlet var pageControl: UIPageControl!
@IBOutlet var contentImageView: UIImageView!

var index     = 0
var heading   = ""
var content   = ""
var imageFile = ""

override func viewDidLoad() 
    super.viewDidLoad()

    headingLabel.text = heading
    contentLabel.text = content
    contentImageView.image = UIImage(named: imageFile)

    // Update the 'currentPage' property of the page control.
    pageControl.currentPage = index

    if case 0...1 = index 
        forwardButton.setTitle("NEXT", for : .normal)
     else if case 2 = index 
        forwardButton.setTitle("DONE", for : .normal)
    


// MARK: - Actions

@IBAction func nextButtonTapped(sender: UIButton) 
    switch index 
    case 0...1: /* Get the parent controller & call to the "forward" method from the 'WalkthroughPageViewController'. */
        let pageViewController = parent as! WalkthroughPageViewController
        pageViewController.forward(index: index)
    case 2: /* Dismiss the page view controller and show the main screen of the app*/
        dismiss(animated: true, completion: nil)
    default: break
    

【讨论】:

【参考方案11】:

只需查看苹果的文档 (https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit) -> 第 3 节 -> 第 5 步

可以这样获取当前索引

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 
            if completed,
                let visibleViewController = pageViewController.viewControllers?.first,
                let index = parent.controllers.firstIndex(of: visibleViewController)
            
                parent.currentPage = index
            
        

或者如果你将 viewControllers 保存在一个数组中,你可以这样做

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 
        if completed,
            let visibleViewController = pageViewController.viewControllers?.first,
            let index = orderedViewControllers.firstIndex(of: visibleViewController)
        
            statisticsPageDelegate?.statisticsPageViewController(statisticsPageViewController: self, didUpdatePageIndex: index)
        
    

这是完整的代码

class StatisticsPageViewController: UIPageViewController,UIPageViewControllerDataSource, UIPageViewControllerDelegate 

    var currentIndex: Int?
    var statisticsPageDelegate: StatisticsPageViewControllerDelegate?
    private var pendingIndex: Int?

    required init?(coder aDecoder: NSCoder) 
        super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
    
    override func viewDidLoad() 
        super.viewDidLoad()
        dataSource = self
        delegate = self

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

        statisticsPageDelegate?.statisticsPageViewController(
            statisticsPageViewController: self,
            didUpdatePageCount: orderedViewControllers.count
        )
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    

    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
        

        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
        

        return orderedViewControllers[nextIndex]
    

    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 
        if completed,
            let visibleViewController = pageViewController.viewControllers?.first,
            let index = orderedViewControllers.firstIndex(of: visibleViewController)
        
            statisticsPageDelegate?.statisticsPageViewController(statisticsPageViewController: self, didUpdatePageIndex: index)
        
    

    private(set) lazy var orderedViewControllers: [UIViewController] = 
        return [self.newStatisticsViewController(identifier: Identifiers.PROGRAM_VIEW_CONTROLLER),
        self.newStatisticsViewController(identifier: Identifiers.LOGIN_VIEW_CONTROLLER)]
    ()

    private func newStatisticsViewController(identifier: String) -> UIViewController 
        return UIStoryboard(name: "Main", bundle: nil) .
            instantiateViewController(withIdentifier: identifier)
    


protocol StatisticsPageViewControllerDelegate: class 
    func statisticsPageViewController(statisticsPageViewController:
        StatisticsPageViewController, didUpdatePageCount count: Int)
    func statisticsPageViewController(statisticsPageViewController:
        StatisticsPageViewController, didUpdatePageIndex index: Int)

【讨论】:

【参考方案12】:

使用viewDidAppear 将页面标记为可见,viewDidDisappear 将页面标记为不可见

项目视图控制器:

class PageItemViewController: UIViewController 

    private(set) var isVisible: Bool = false

    override func viewDidAppear(_ animated: Bool) 
        super.viewDidAppear(animated)
        isVisible = true
    

    override func viewDidDisappear(_ animated: Bool) 
        super.viewDidDisappear(animated)
        isVisible = false
       

获取可见页面的索引

class PageViewController: UIPageViewController, UIPageViewControllerDelegate 

    var items: [PageItemViewController] = [] 
        didSet 
            if let last = items.last 
                setViewControllers([last], direction: .forward, animated: true, completion: nil)
            
        
    

    // ...

    public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 
        if finished 
            guard let currentIndex = items.firstIndex(where:  $0.isVisible ) else  return 
            print(currentIndex)
        
    

【讨论】:

以上是关于Swift 中的 PageViewController 当前页面索引的主要内容,如果未能解决你的问题,请参考以下文章

Swift 4 或 Swift 5 中的 UITextView 用户输入文本验证:限制 Swift 中的特定字符

swift: Swift 中的 SnapKit 不起作用

swift中的 isKindofClass

swift Swift中的变量

swift Swift中的数组

swift SWIFT中的变量