如何使用带有现有 UIPageViewController 的按钮以编程方式滑动视图
How Can I slide Views programmatically using buttons with existing UIPageViewController
我正在开发一个有 3 个主视图的应用程序,为了让用户只需滑动即可更改 3 个视图(如 Tinder 应用程序),我创建了一个 PageViewController,它运行良好。这个 PageViewController 的工作原理如下。
- 当用户点击 "Login" 或 "SignUp" 按钮时,它会转到 PageViewController
- PageViewController 将 firstViewController 设置为初始视图
- 在PageViewController中,有3个方法分别是「getFirst」(获取第一个ViewController)、「getSecond」(获取第二个ViewController)、
「getThird」(获取第三个ViewController)。
我还在每 3 个视图的上侧添加了按钮,并希望用户能够点击这些按钮以滑动到其他视图,就像他们滑动这些视图时一样(这也像 Tinder)。
所以为了实验,我在 SecondViewController 上添加了两个按钮。左边一个用于移动到 FirstViewController,右边一个用于移动到 ThirdViewController。
然后,在 SecondViewController 文件中,我添加了 "UIPageViewControllerDelegate" 并尝试从 PageViewController 文件中为左按钮调用“getFirst”方法,为右按钮调用“getThird”方法。
但是当我点击左键时,我在 PageViewController 文件中的“getFirst”方法行收到了这个错误消息(我可能也会在右键时遇到同样的错误)。
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
代码如下。
PageViewController
import UIKit
class PageViewController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.setViewControllers([getFirst()], direction: .forward, animated: true, completion: nil)
self.dataSource = self as UIPageViewControllerDataSource
}
}
extension PageViewController : UIPageViewControllerDataSource {
//FirstViewController
@objc func getFirst() -> FirstViewController {
return storyboard!.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController
}
//SecondViewController
@objc func getSecond() -> SecondViewController {
return storyboard!.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
}
//ThirdViewController
@objc func getThird() -> ThirdViewController {
return storyboard!.instantiateViewController(withIdentifier: "ThirdViewController") as! ThirdViewController
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
if viewController.isKind(of: ThirdViewController.self) {
// 3 -> 2
return getSecond()
} else if viewController.isKind(of: SecondViewController.self) {
// 2 -> 1
return getFirst()
} else {
// 1 -> end of the road
return nil
}
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
if viewController.isKind(of: FirstViewController.self) {
// 1 -> 2
return getSecond()
} else if viewController.isKind(of: SecondViewController.self) {
// 2 -> 3
return getThird()
} else {
// 3 -> end of the road
return nil
}
}
}
第二视图控制器
import UIKit
class SecondViewController: UIViewController, UIPageViewControllerDelegate {
let pageHelper = PageViewController()
override func viewDidLoad() {
super.viewDidLoad()
pageHelper.delegate = self
}
@IBAction func toFirstTapped(_ sender: Any) {
pageHelper.getFirst()
}
}
我错过了什么??也许我不能让它以这种方式工作(我不能重用其他文件中的 PageViewController?)。
有人能帮帮我吗!
首先,PageViewController
实例化一个子控制器,它实例化一个 PageViewController
.. 这真的是个好主意吗?然后在你的 toFirstTapped
中,你实例化了一个 FirstViewController
但什么都不做..
如果您什么都不做,您期望它如何工作?
无论如何,请尝试以下操作:
protocol PageNavigationDelegate : class {
weak var pageController: PageViewController? { get set }
}
class PageViewController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.setViewControllers([getFirst()], direction: .forward, animated: true, completion: nil)
self.dataSource = self as UIPageViewControllerDataSource
}
}
extension PageViewController : UIPageViewControllerDataSource {
func getFirst() -> FirstViewController {
let controller = storyboard!.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController
controller.pageController = self
return controller
}
func getSecond() -> SecondViewController {
let controller = storyboard!.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
controller.pageController = self
return controller
}
func getThird() -> ThirdViewController {
let controller = storyboard!.instantiateViewController(withIdentifier: "ThirdViewController") as! ThirdViewController
controller.pageController = self
return controller
}
@discardableResult
func goToPreviousPage() -> Bool {
let controller = self.viewControllers!.first!
if controller.isKind(of: SecondViewController.self) {
self.setViewControllers([getFirst()], direction: .reverse, animated: true, completion: nil)
return true
}
if controller.isKind(of: ThirdViewController.self) {
self.setViewControllers([getSecond()], direction: .reverse, animated: true, completion: nil)
return true
}
return false
}
@discardableResult
func goToNextPage() -> Bool {
let controller = self.viewControllers!.first!
if controller.isKind(of: FirstViewController.self) {
self.setViewControllers([getSecond()], direction: .forward, animated: true, completion: nil)
return true
}
if controller.isKind(of: SecondViewController.self) {
self.setViewControllers([getThird()], direction: .forward, animated: true, completion: nil)
return true
}
return false
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
if viewController.isKind(of: SecondViewController.self) {
return getFirst()
}
if viewController.isKind(of: ThirdViewController.self) {
return getSecond()
}
return nil
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
if viewController.isKind(of: FirstViewController.self) {
return getSecond()
}
if viewController.isKind(of: SecondViewController.self) {
return getThird()
}
return nil
}
}
class PageNavigationController : UIViewController, PageNavigationDelegate {
var pageController: PageViewController?
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func goToPreviousController(_ sender: Any) {
pageController?.goToPreviousPage()
}
@IBAction func goToNextController(_ sender: Any) {
pageController?.goToNextPage()
}
}
class FirstViewController: PageNavigationController {
}
class SecondViewController: PageNavigationController {
}
class ThirdViewController: PageNavigationController {
}
首先我们创建了一个协议。我们确保所有 PageController 的子控制器都将实现它。这样,他们就可以导航到上一页和下一页..
接下来,我们创建具有 goToPreviousPage
和 goToNextPage
函数的扩展。当我们实例化每个控制器页面时,我们将 self
分配给它的协议实现变量。这样,控制器就可以访问 PageViewController
的方法..
最后,在我们的 First
、Second
和 Third
控制器中,我们只需告诉它在按下按钮时前进或后退。
就我个人而言,我更喜欢跟踪数组中的控制器,而只是 return 我的代表中的控制器。
我正在开发一个有 3 个主视图的应用程序,为了让用户只需滑动即可更改 3 个视图(如 Tinder 应用程序),我创建了一个 PageViewController,它运行良好。这个 PageViewController 的工作原理如下。
- 当用户点击 "Login" 或 "SignUp" 按钮时,它会转到 PageViewController
- PageViewController 将 firstViewController 设置为初始视图
- 在PageViewController中,有3个方法分别是「getFirst」(获取第一个ViewController)、「getSecond」(获取第二个ViewController)、 「getThird」(获取第三个ViewController)。
我还在每 3 个视图的上侧添加了按钮,并希望用户能够点击这些按钮以滑动到其他视图,就像他们滑动这些视图时一样(这也像 Tinder)。
所以为了实验,我在 SecondViewController 上添加了两个按钮。左边一个用于移动到 FirstViewController,右边一个用于移动到 ThirdViewController。 然后,在 SecondViewController 文件中,我添加了 "UIPageViewControllerDelegate" 并尝试从 PageViewController 文件中为左按钮调用“getFirst”方法,为右按钮调用“getThird”方法。
但是当我点击左键时,我在 PageViewController 文件中的“getFirst”方法行收到了这个错误消息(我可能也会在右键时遇到同样的错误)。
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
代码如下。
PageViewController
import UIKit
class PageViewController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.setViewControllers([getFirst()], direction: .forward, animated: true, completion: nil)
self.dataSource = self as UIPageViewControllerDataSource
}
}
extension PageViewController : UIPageViewControllerDataSource {
//FirstViewController
@objc func getFirst() -> FirstViewController {
return storyboard!.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController
}
//SecondViewController
@objc func getSecond() -> SecondViewController {
return storyboard!.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
}
//ThirdViewController
@objc func getThird() -> ThirdViewController {
return storyboard!.instantiateViewController(withIdentifier: "ThirdViewController") as! ThirdViewController
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
if viewController.isKind(of: ThirdViewController.self) {
// 3 -> 2
return getSecond()
} else if viewController.isKind(of: SecondViewController.self) {
// 2 -> 1
return getFirst()
} else {
// 1 -> end of the road
return nil
}
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
if viewController.isKind(of: FirstViewController.self) {
// 1 -> 2
return getSecond()
} else if viewController.isKind(of: SecondViewController.self) {
// 2 -> 3
return getThird()
} else {
// 3 -> end of the road
return nil
}
}
}
第二视图控制器
import UIKit
class SecondViewController: UIViewController, UIPageViewControllerDelegate {
let pageHelper = PageViewController()
override func viewDidLoad() {
super.viewDidLoad()
pageHelper.delegate = self
}
@IBAction func toFirstTapped(_ sender: Any) {
pageHelper.getFirst()
}
}
我错过了什么??也许我不能让它以这种方式工作(我不能重用其他文件中的 PageViewController?)。
有人能帮帮我吗!
首先,PageViewController
实例化一个子控制器,它实例化一个 PageViewController
.. 这真的是个好主意吗?然后在你的 toFirstTapped
中,你实例化了一个 FirstViewController
但什么都不做..
如果您什么都不做,您期望它如何工作?
无论如何,请尝试以下操作:
protocol PageNavigationDelegate : class {
weak var pageController: PageViewController? { get set }
}
class PageViewController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.setViewControllers([getFirst()], direction: .forward, animated: true, completion: nil)
self.dataSource = self as UIPageViewControllerDataSource
}
}
extension PageViewController : UIPageViewControllerDataSource {
func getFirst() -> FirstViewController {
let controller = storyboard!.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController
controller.pageController = self
return controller
}
func getSecond() -> SecondViewController {
let controller = storyboard!.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
controller.pageController = self
return controller
}
func getThird() -> ThirdViewController {
let controller = storyboard!.instantiateViewController(withIdentifier: "ThirdViewController") as! ThirdViewController
controller.pageController = self
return controller
}
@discardableResult
func goToPreviousPage() -> Bool {
let controller = self.viewControllers!.first!
if controller.isKind(of: SecondViewController.self) {
self.setViewControllers([getFirst()], direction: .reverse, animated: true, completion: nil)
return true
}
if controller.isKind(of: ThirdViewController.self) {
self.setViewControllers([getSecond()], direction: .reverse, animated: true, completion: nil)
return true
}
return false
}
@discardableResult
func goToNextPage() -> Bool {
let controller = self.viewControllers!.first!
if controller.isKind(of: FirstViewController.self) {
self.setViewControllers([getSecond()], direction: .forward, animated: true, completion: nil)
return true
}
if controller.isKind(of: SecondViewController.self) {
self.setViewControllers([getThird()], direction: .forward, animated: true, completion: nil)
return true
}
return false
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
if viewController.isKind(of: SecondViewController.self) {
return getFirst()
}
if viewController.isKind(of: ThirdViewController.self) {
return getSecond()
}
return nil
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
if viewController.isKind(of: FirstViewController.self) {
return getSecond()
}
if viewController.isKind(of: SecondViewController.self) {
return getThird()
}
return nil
}
}
class PageNavigationController : UIViewController, PageNavigationDelegate {
var pageController: PageViewController?
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func goToPreviousController(_ sender: Any) {
pageController?.goToPreviousPage()
}
@IBAction func goToNextController(_ sender: Any) {
pageController?.goToNextPage()
}
}
class FirstViewController: PageNavigationController {
}
class SecondViewController: PageNavigationController {
}
class ThirdViewController: PageNavigationController {
}
首先我们创建了一个协议。我们确保所有 PageController 的子控制器都将实现它。这样,他们就可以导航到上一页和下一页..
接下来,我们创建具有 goToPreviousPage
和 goToNextPage
函数的扩展。当我们实例化每个控制器页面时,我们将 self
分配给它的协议实现变量。这样,控制器就可以访问 PageViewController
的方法..
最后,在我们的 First
、Second
和 Third
控制器中,我们只需告诉它在按下按钮时前进或后退。
就我个人而言,我更喜欢跟踪数组中的控制器,而只是 return 我的代表中的控制器。