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 设置为正确的索引(我想我必须在两个函数 viewControllerBefore
和 viewControllerAfter
中设置它?
我尝试使用 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
}
}
我正在尝试让 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 设置为正确的索引(我想我必须在两个函数 viewControllerBefore
和 viewControllerAfter
中设置它?
我尝试使用 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
}
}