【问题标题】:How Can I slide Views programmatically using buttons with existing UIPageViewController如何使用现有 UIPageViewController 的按钮以编程方式滑动视图
【发布时间】:2018-01-01 16:21:57
【问题描述】:

我正在开发一个具有 3 个主视图的应用程序,为了使用户能够通过滑动来更改 3 个视图(如 Tinder 应用程序),我创建了一个 PageViewController,它运行良好。这个 PageViewController 的工作原理如下。

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

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

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

但是当我点击左边的按钮时,我在 PageViewController 文件的「getFirst」方法行上收到了这个错误消息(我可能也会在右边的按钮上得到同样的错误)。

线程 1:致命错误:在展开可选值时意外发现 nil

代码如下。

页面视图控制器

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?)。

有人可以帮帮我吗!

【问题讨论】:

    标签: ios swift uipageviewcontroller


    【解决方案1】:

    首先,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 的子控制器都会实现它。这样,他们可以导航到上一页和下一页。

    接下来,我们创建具有goToPreviousPagegoToNextPage 函数的扩展。当我们实例化每个控制器页面时,我们将self 分配给它的协议实现变量。这样,控制器可以访问PageViewController 的方法..

    最后,在我们的 FirstSecondThird 控制器中,我们只是告诉它在按下按钮时前进或后退。

    就个人而言,我更喜欢在数组中跟踪控制器,然后在我的委托中返回这些控制器。

    【讨论】:

    • 嗨,布兰登。非常感谢您的回答!由于我对 Swift 很陌生,所以我有一些问题(抱歉,它们可能是非常基本的东西)。首先,我认为我需要在 3 个文件(First、Second、Third ViewControllers)中的每一个中定义 pageController,并且您在 PageViewController 类下方编写了“class PageNavigationController:UIViewController,PageNavigationDelegate”。你的意思是我必须将它实现到 3 个文件(第一、第二、第三个 ViewControllers)中?我不太确定我应该在哪里写那门课……
    • @George;您可以在所有子类 FirstSecondThird 中实现它,或者您可以像我上面所做的那样继承并将出口拖到所有 3 个控制器的父函数。
    • 哦,我明白了!非常感谢您的帮助!我试试看
    猜你喜欢
    • 2016-08-01
    • 1970-01-01
    • 2012-11-19
    • 2019-11-21
    • 2019-08-07
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    • 1970-01-01
    相关资源
    最近更新 更多