ios - 如何使用带有现有 UIPageViewController 的按钮以编程方式滑动 View

标签 ios swift uipageviewcontroller

我正在开发一个具有 3 个主视图的应用程序,为了让用户只需滑动即可更改 3 个 View (如 Tinder 应用程序),我创建了一个 PageViewController,它运行良好。这个 PageViewController 的工作方式如下。

  1. 当用户点击“登录”或“注册”按钮时,它转到 PageViewController
  2. PageViewController 将 firstViewController 设置为初始 View
  3. 在PageViewController中,有3个方法分别是「getFirst」(获取第一个ViewController)、「getSecond」(获取第二个ViewController)、 「getThird」(获取第三个ViewController)。

我还在每 3 个 View 的上侧添加了按钮,并希望用户能够点击这些按钮以滑动到其他 View ,就像他们滑动这些 View 时所做的那样(这也类似于 Tinder)。

所以为了实验,我在 SecondViewController 上添加了两个按钮。左边一个用于移动到 FirstViewController,右边一个用于移动到 ThirdViewController。 然后,在 SecondViewController 文件中,我添加了“UIPageViewControllerDelegate”并尝试从 PageViewController 文件中为左按钮调用“getFirst”方法,为右按钮调用“getThird”方法。

但是当我点击左键时,我在 PageViewController 文件中的“getFirst”方法行收到了这个错误消息(我可能也会在右键时遇到同样的错误)。

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

代码如下。

页面 View Controller

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
        }
    }
}

第二 View Controller

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 实例化一个子 Controller ,子 Controller 又实例化一个 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 {

}

首先我们创建了一个协议(protocol)。我们确保所有 PageController 的子 Controller 都将实现它。这样,他们就可以导航到上一页和下一页。

接下来,我们创建具有 goToPreviousPagegoToNextPage 功能的扩展。当我们实例化每个 Controller 页面时,我们将 self 分配给它的协议(protocol)实现变量。这样, Controller 就可以访问 PageViewController 的方法..

最后,在我们的 FirstSecondThird Controller 中,我们只需告诉它在按下按钮时前进或后退。

就我个人而言,我更愿意跟踪数组中的 Controller 并只在我的委托(delegate)中返回它们。

关于ios - 如何使用带有现有 UIPageViewController 的按钮以编程方式滑动 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48051275/

相关文章:

ios - 如何处理由 viewWillTransitionToSize 函数旋转的 UIPageViewController VC?

ios - 将加密 key 存储在 defaultConfiguration 中是否安全?

ios - Swift 3 - UIPageViewController 实现返回空(空白) View

ios - Collection View cellForItemAt indexPath 未被调用(Swift)

ios - Swift 删除对 UIView 的引用

ios - 触发通知屏幕锁定

swift - 如何快速在两个 View 上使用滑动手势

ios - 在旋转时移除 UIPageViewController 上的 pageIndicator

ios - 如何在 iOS 中检查损坏的 PDF?

html - CSS3 Grid-gap 不适用于 iphone