Swift:从其他视图控制器调用 PageViewController 中的函数

Posted

技术标签:

【中文标题】Swift:从其他视图控制器调用 PageViewController 中的函数【英文标题】:Swift: Call Function in PageViewController from other Viewcontroller 【发布时间】:2017-02-24 01:17:34 【问题描述】:

我有一个 PageViewController,它加载两个“子”ViewController,以便让用户“滑动”它们。我不想要这种滑动手势,而是希望在我的 ViewController 中有一个函数,它允许我在 PageViewController 中使用 setViewControllers。

我尝试使用协议,但即使这样也没有成功。

对于如何实现这一点,我非常感谢任何帮助或建议。谢谢!

【问题讨论】:

【参考方案1】:

要从您的子视图控制器访问 setViewController,您需要您的子视图控制器知道它们的父 PageViewController。要做到这一点,首先要制定一个协议(我知道你说过你已经尝试过协议,但请看我的方法)。该协议将确保每个子视图控制器都有对父 PageViewController 的引用。

    protocol PageObservation: class 
        func getParentPageViewController(parentRef: PageViewController)
    

确保您的子视图控制器遵守 PageObservation 协议。

    class Child1ViewController: UIViewController, PageObservation 
        var parentPageViewController: PageViewController!
        func getParentPageViewController(parentRef: PageViewController) 
            parentPageViewController = parentRef
        
    

    class Child2ViewController: UIViewController, PageObservation 
        var parentPageViewController: PageViewController!
        func getParentPageViewController(parentRef: PageViewController) 
            parentPageViewController = parentRef
        
    

在您的 PageViewController 中,当您创建每个子视图控制器时,将它们转换为 PageObservation 类型并传递父 PageViewController 的引用。我使用一个名为 orderViewControllers 的数组来创建我的页面。我的 UIPageViewControllerDataSource 委托方法使用它来知道要加载哪些页面,但这与本示例无关,我只是想我会告诉你,以防你有不同的创建页面的方式。

    class PageViewController: UIPageViewController 
        var orderedViewControllers: [UIViewController] = []


        //creating child 1
        //i am using storyboard to create the child view controllers, I have given them the identifiers Child1ViewController and Child2ViewController respectively
        let child1ViewController =  UIStoryboard(name: "Main", bundle: nil) .
        instantiateViewController(withIdentifier: "Child1ViewController")
        let child1WithParent = child1ViewController as! PageObservation
        child1WithParent.getParentPageViewController(parentRef: self)

        orderedViewControllers.append(child1ViewController)

        //creating child 2
        let child2ViewController =  UIStoryboard(name: "Main", bundle: nil) .
        instantiateViewController(withIdentifier: "Child2ViewController")
        let child2WithParent = child2ViewController as! PageObservation
        child2WithParent.getParentPageViewController(parentRef: self)

        orderedViewControllers.append(child2ViewController)
    

现在在您的子视图控制器中,您可以访问 setViewControllers。例如,如果我想在 child1ViewController 中调用 setViewControllers,我创建了一个名为 accessSetViewControllers() 的函数,我可以在其中访问 setViewControllers:

    class Child1ViewController: UIViewController, PageObservation 
         var parentPageViewController: PageViewController!
        func getParentPageViewController(parentRef: PageViewController) 
            parentPageViewController = parentRef
        

        func accessSetViewControllers() 
             parentPageViewController.setViewControllers( //do what you need )
        
    

附带说明,尽管上面的其他答案已经说过,您可以将 dataSource 设置为您喜欢的任何内容。我有时将 dataSource 设置为 nil 以防止用户在执行某项操作之前从屏幕上滑动,然后将 dataSource 添加回来以允许他们继续滑动。

【讨论】:

感谢您的回答。但是您的代码中的“pageViewController”是什么?您在创建子控制器时使用它。 我尝试了您的解决方案,似乎一切正常!迄今为止在网上找到的最佳答案!但是,我还有一个问题:假设我有 3 个子视图控制器,每个子视图控制器都嵌入在自己的导航控制器中。那么如何“创建子控制器”呢?仅使用 Navigation Controller - Storyboard - ID 引用它们不起作用。我是否必须更改其他内容?最好的问候,非常感谢! 如果我理解正确的话,您有一个 PageViewController 和三个孩子,但每个孩子都有自己的导航控制器,对吧?您不需要引用导航控制器来创建子项。您只需要给孩子一个标识符并从中实例化它,孩子就会知道它自己有一个导航控制器。对于具有标识符“child”但嵌入在导航控制器中的孩子,您可以这样做: let childVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "child") as! ChildViewController 我今天尝试了您的建议,但无法正常运行。应用程序因 Signal 1 Sigabrt 或奇怪的展开错误而崩溃。你能给我一个工作示例吗?我真的很感激。很抱歉我一直在问我的问题,但我对 Swift 还很陌生,但我仍在努力学习很多东西! 很乐意提供帮助,但也许我是不了解您想要实现的目标的人。我认为最好将这个问题作为一个问题放在 Stack 上,我或任何人都可以尝试回答它。一些提示:如果可能,添加图表,添加您已经尝试但不起作用的代码,提及 Stack 上任何不适合您的解决方案。【参考方案2】:

不要设置dataSource。当它为 nil 时,手势将不起作用。

https://developer.apple.com/reference/uikit/uipageviewcontroller

定义页面视图控制器接口时,您可以一次提供一个(或一次提供两个,取决于书脊位置和双面状态)或使用数据源按需提供内容视图控制器。当一次提供一个内容视图控制器时,您使用setViewControllers(_:direction:animated:completion:) 方法来设置当前的内容视图控制器。 要支持基于手势的导航,您必须使用数据源对象提供视图控制器。

【讨论】:

是的,我已经读过。问题是,我不知道如何从我的子 ViewControllers 中调用“setViewControllers”。不管怎样,谢谢你的回复 如果您使用goBack/goForward 之类的方法创建一个委托协议并为您的子VC添加一个弱属性会更好。之后,让您的父 VC 成为您子 VC 的代表。在这种情况下,您不需要直接从孩子那里致电setViewControllers,他们不会知道任何关于 Page VC 的信息 我会试试的!也许它有效,如果它这样做,你真的是一个更安全的生活!【参考方案3】:

简单的方法...删除pageViewController的viewDidLoad中内置的手势识别器:

for view in self.pageViewController!.view.subviews 
   if let subView = view as? UIScrollView 
       subView.scrollEnabled = false
   

然后在其下方添加您自己的手势。我只是碰巧正在使用双击,但你可以让它向左滑动,向右滑动很容易:

let doubleTap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didDoubleTap))
doubleTap.numberOfTapsRequired = 2
doubleTap.delaysTouchesBegan = true
self.addGestureRecognizer(doubleTap)

以及您的代码中的手势功能:

func didDoubleTap(gesture: UITapGestureRecognizer) 

//... stuff


【讨论】:

以上是关于Swift:从其他视图控制器调用 PageViewController 中的函数的主要内容,如果未能解决你的问题,请参考以下文章

不能在代码中调用 segue (Swift)

从 Swift 中的其他类调用方法

Swift 从视图控制器调用一个类

是否可以使用情节提要从 swift 类中调用 Objective c 视图控制器类?

swift3如何显示导航视图控制器

在主视图控制器中显示警报视图(从子类调用)