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) -> 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 版本
使用这些协议(UIPageViewControllerDelegate
、UIPageViewControllerDataSource
)扩展 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 当前页面索引的主要内容,如果未能解决你的问题,请参考以下文章