如何从 UIPageViewController 中的视图控制器返回上一个 VC 或下一个 VC?
how to be back to previous VC or next VC from a view controller inside UIPageViewController?
我有 3 个由 UIPageViewController 控制的视图控制器,如下图所示
https://i.stack.imgur.com/9Lqoj.png
如果我滑动屏幕,它会从 RedVC 移动到 BlueVC 再到 YellowVC。
我想在 BlueVC 中制作下一步按钮和后退按钮 。所以如果用户按下后退按钮,它将转到 RedVC,如果用户按下下一步按钮,它将转到 YellowVC。怎么做?
这是我在根页面视图控制器中的代码:
import UIKit
class RootPageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
lazy var viewControllerList : [UIViewController] = {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let redVC = storyBoard.instantiateViewController(withIdentifier: "redVC")
let blueVC = storyBoard.instantiateViewController(withIdentifier: "blueVC")
let yellowVC = storyBoard.instantiateViewController(withIdentifier: "yellowVC")
return [redVC,blueVC,yellowVC]
}()
// to add dot indicator
var pageControl = UIPageControl()
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
configurePageControl()
turnIntoPage()
}
func turnIntoPage() {
// set view controllers to be pages
if let firstViewController = viewControllerList.first {
// if so then set the direction
self.setViewControllers([firstViewController], direction: .forward, animated: true, completion: nil)
}
}
// MARK: - Page View Controller Data Source functions
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
// a method that will handle view controller before current view controller
// make precaution , if the lodic is wrong then return nil (prevent index out of logic)
guard let vcIndex = viewControllerList.index(of: viewController) else { return nil}
let previousIndex = vcIndex - 1
guard previousIndex >= 0 else { return nil}
guard viewControllerList.count > previousIndex else {return nil}
// return the value
return viewControllerList[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
// a method that will handle view controller after current view controller
// make precaution , if the lodic is wrong then return nil (prevent index out of logic)
guard let vcIndex = viewControllerList.index(of: viewController) else { return nil}
let nextIndex = vcIndex + 1
guard viewControllerList.count != nextIndex else {return nil}
guard viewControllerList.count > nextIndex else {return nil}
// return the value
return viewControllerList[nextIndex]
}
// to add dot indicator
// MARK: Page View Controller Delegate functions
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
let pageContentViewController = pageViewController.viewControllers![0]
self.pageControl.currentPage = viewControllerList.index(of: pageContentViewController)!
}
func configurePageControl() {
// The total number of pages that are available is based on how many available colors we have.
pageControl = UIPageControl(frame: CGRect(x: 0,y: UIScreen.main.bounds.maxY - 50,width: UIScreen.main.bounds.width,height: 50))
self.pageControl.numberOfPages = viewControllerList.count
self.pageControl.currentPage = 0
self.pageControl.tintColor = UIColor.black
self.pageControl.pageIndicatorTintColor = UIColor.white
self.pageControl.currentPageIndicatorTintColor = UIColor.black
self.view.addSubview(pageControl)
}
}
因此,在您的 RootPageViewController
中,您可以在那里拥有一个将使用 setViewControllers
的函数。
setViewControllers
被描述为:
// Set visible view controllers, optionally with animation. Array
should only include view controllers that will be visible after the
animation has completed.
// For transition style 'UIPageViewControllerTransitionStylePageCurl', if 'doubleSided' is
'YES' and the spine location is not
'UIPageViewControllerSpineLocationMid', two view controllers must be
included, as the latter view controller is used as the back.
所以让我们尝试使用 Next
函数。
func next() {
let vcs = self.viewControllerList
//or self.viewControllers
let currentPage = self.pageControl.currentPage
let nextPage = currentPage + 1
if nextPage < vcs.count {
let nextVC = vcs[nextPage]
self.setViewControllers([nextVC], direction: .forward, animated: true) { _ in
self.pageControl.currentPage = nextPage
}
}
}
如您所见,我们正在安全地从您在代码中创建的 vcs
中获取 viewController,其中包含所有页面。在我们得到下一个 viewController 之后,如果有的话,我们使用 setViewControllers
。为了让它变得更好,我们正在设置 pageControl
的 currentPage
来告诉 pageController 底部的哪个圆圈要着色。
然后从您的 BlueVC
获取您的 pageController 的引用。如何?通过访问 self.parent
并将其转换为您的 RootPageViewController
。像这样:
@IBAction func next(_ sender: Any) {
if let parentVC = self.parent as? RootPageViewController {
parentVC.next()
}
}
现在,您的任务是实现 previous
功能。
我有 3 个由 UIPageViewController 控制的视图控制器,如下图所示
如果我滑动屏幕,它会从 RedVC 移动到 BlueVC 再到 YellowVC。
我想在 BlueVC 中制作下一步按钮和后退按钮 。所以如果用户按下后退按钮,它将转到 RedVC,如果用户按下下一步按钮,它将转到 YellowVC。怎么做?
这是我在根页面视图控制器中的代码:
import UIKit
class RootPageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
lazy var viewControllerList : [UIViewController] = {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let redVC = storyBoard.instantiateViewController(withIdentifier: "redVC")
let blueVC = storyBoard.instantiateViewController(withIdentifier: "blueVC")
let yellowVC = storyBoard.instantiateViewController(withIdentifier: "yellowVC")
return [redVC,blueVC,yellowVC]
}()
// to add dot indicator
var pageControl = UIPageControl()
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
configurePageControl()
turnIntoPage()
}
func turnIntoPage() {
// set view controllers to be pages
if let firstViewController = viewControllerList.first {
// if so then set the direction
self.setViewControllers([firstViewController], direction: .forward, animated: true, completion: nil)
}
}
// MARK: - Page View Controller Data Source functions
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
// a method that will handle view controller before current view controller
// make precaution , if the lodic is wrong then return nil (prevent index out of logic)
guard let vcIndex = viewControllerList.index(of: viewController) else { return nil}
let previousIndex = vcIndex - 1
guard previousIndex >= 0 else { return nil}
guard viewControllerList.count > previousIndex else {return nil}
// return the value
return viewControllerList[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
// a method that will handle view controller after current view controller
// make precaution , if the lodic is wrong then return nil (prevent index out of logic)
guard let vcIndex = viewControllerList.index(of: viewController) else { return nil}
let nextIndex = vcIndex + 1
guard viewControllerList.count != nextIndex else {return nil}
guard viewControllerList.count > nextIndex else {return nil}
// return the value
return viewControllerList[nextIndex]
}
// to add dot indicator
// MARK: Page View Controller Delegate functions
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
let pageContentViewController = pageViewController.viewControllers![0]
self.pageControl.currentPage = viewControllerList.index(of: pageContentViewController)!
}
func configurePageControl() {
// The total number of pages that are available is based on how many available colors we have.
pageControl = UIPageControl(frame: CGRect(x: 0,y: UIScreen.main.bounds.maxY - 50,width: UIScreen.main.bounds.width,height: 50))
self.pageControl.numberOfPages = viewControllerList.count
self.pageControl.currentPage = 0
self.pageControl.tintColor = UIColor.black
self.pageControl.pageIndicatorTintColor = UIColor.white
self.pageControl.currentPageIndicatorTintColor = UIColor.black
self.view.addSubview(pageControl)
}
}
因此,在您的 RootPageViewController
中,您可以在那里拥有一个将使用 setViewControllers
的函数。
setViewControllers
被描述为:
// Set visible view controllers, optionally with animation. Array should only include view controllers that will be visible after the animation has completed. // For transition style 'UIPageViewControllerTransitionStylePageCurl', if 'doubleSided' is 'YES' and the spine location is not 'UIPageViewControllerSpineLocationMid', two view controllers must be included, as the latter view controller is used as the back.
所以让我们尝试使用 Next
函数。
func next() {
let vcs = self.viewControllerList
//or self.viewControllers
let currentPage = self.pageControl.currentPage
let nextPage = currentPage + 1
if nextPage < vcs.count {
let nextVC = vcs[nextPage]
self.setViewControllers([nextVC], direction: .forward, animated: true) { _ in
self.pageControl.currentPage = nextPage
}
}
}
如您所见,我们正在安全地从您在代码中创建的 vcs
中获取 viewController,其中包含所有页面。在我们得到下一个 viewController 之后,如果有的话,我们使用 setViewControllers
。为了让它变得更好,我们正在设置 pageControl
的 currentPage
来告诉 pageController 底部的哪个圆圈要着色。
然后从您的 BlueVC
获取您的 pageController 的引用。如何?通过访问 self.parent
并将其转换为您的 RootPageViewController
。像这样:
@IBAction func next(_ sender: Any) {
if let parentVC = self.parent as? RootPageViewController {
parentVC.next()
}
}
现在,您的任务是实现 previous
功能。