如何使用现有UIPageViewController的按钮以编程方式滑动视图

时间:2018-01-01 16:21:58

标签: ios swift uipageviewcontroller

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

  1. 当用户点击"登录"或" SignUp"按钮,它将分段到PageViewController
  2. PageViewController将firstViewController设置为初始View
  3. 在PageViewController中,有3个方法是“getFirst”(获取firstViewController),“getSecond”(获取secondViewController), 「getThird」(获取第三个ViewController)。
  4. 我还在每个3个视图的上方添加了按钮,并希望用户能够点击这些按钮滑动到其他视图,就像它们滑动那些视图时一样(这也像Tinder)。

    因此,对于实验,我在SecondViewController上添加了两个按钮。左边是移动到FirstViewController,右边是移动到ThirdViewController。 然后,在SecondViewController文件中,我添加了" UIPageViewControllerDelegate"并试图为左键调用「getFirst」方法,并从PageViewController文件中调用右键的「getThird」方法。

    但是当我点击左键时,我在PageViewController文件的“getFirst”方法行中收到了此错误消息(对于右键,我可能会得到相同的错误)。

      

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

    代码如下。

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

    SecondViewController

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

    请有人帮助我!

1 个答案:

答案 0 :(得分: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控制器中,我们只是告诉它按下按钮前进或后退。

就个人而言,我更愿意跟踪数组中的控制器,并将其返回给我的代表。