在导航堆栈中跳过/添加视图控制器

时间:2015-08-21 08:02:00

标签: ios swift uinavigationcontroller

我在导航控制器中嵌入了三个视图控制器。我想从VC1转到VC3,这样在VC3中导航项的后退按钮会将用户引导到VC2而不是VC1。我认为这应该通过在创建VC3时将VC2添加到VC1和VC3之间的导航堆栈或通过跳过第二个View Controller 来完成。

我试过了:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if let identifier = segue.identifier {
        switch identifier {
        case "JumpToThirdVCSegue":
            if let secondvc = segue.destinationViewController as? SecondViewController {
                secondvc.performSegueWithIdentifier("ThirdVCSegue", sender: self)
            }
        default: break
        }
    }
}
但是我无法让它发挥作用。当视图控制器尚未打开时,也许无法执行segue?

跳过视图控制器/在导航堆栈中间添加视图控制器的最佳方法是什么?我希望这可以帮助你理解我想要做的事情:

6 个答案:

答案 0 :(得分:21)

这样的事情应该有效:

    self.navigationController?.pushViewController(viewController2, animated: true)
    self.navigationController?.pushViewController(viewController3, animated: true)

修改

如果要在不被用户注意的情况下推送第二个视图控制器,则需要在按下第三个视图控制器后将其添加到导航控制器。这可以通过实施UINavigationControllerDelegate来完成。您可以将第二个视图控制器存储在变量中,并将其插入到委托方法中的导航控制器层次结构中。您的主视图控制器将如下所示:

class MyViewController: UIViewController, UINavigationControllerDelegate {

    var viewControllerToInsertBelow : UIViewController?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationController?.delegate = self
    }

    func pushTwoViewControllers() {
        if let viewController2 = self.storyboard?.instantiateViewControllerWithIdentifier("id1"),
            let viewController3 = self.storyboard?.instantiateViewControllerWithIdentifier("id2") { //change this to your identifiers
                self.viewControllerToInsertBelow = viewController2
                self.navigationController?.pushViewController(viewController3, animated: true)
        }
    }

    //MARK: - UINavigationControllerDelegate
    func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
        if let vc = viewControllerToInsertBelow {
            viewControllerToInsertBelow = nil
            let index = navigationController.viewControllers.indexOf(viewController)!
            navigationController.viewControllers.insert(vc, atIndex: index)
        }
    }

}

答案 1 :(得分:6)

编辑:使用swift和segues,这应该有效:

override func performSegueWithIdentifier(identifier: String?, sender: AnyObject?) {
    super.performSegueWithIdentifier(identifier, sender: sender);

    if identifier == "JumpToThirdVCSegue" {
        // now the vc3 was already pushed on the navigationStack
        var navStackArray : [AnyObject]! = self.navigationController!.viewControllers
        // insert vc2 at second last position
        navStackArray.insert(viewController2, atIndex: navStackArray.count - 2)
        // update navigationController viewControllers
        self.navigationController!.setViewControllers(navStackArray, animated:false)
    }
}

所以你覆盖VC1中的performSegueWithIdentifier,以便在实际执行segue到VC3时更改导航堆栈(并且不仅仅是在准备中)。 这假设您要在VC1中处理此特殊导航逻辑。

答案 2 :(得分:3)

if var navstack = navigationController?.viewControllers{
                    navstack.append(contentsOf: [vc1,vc2])
                    navigationController?.setViewControllers(navstack, animated: true)
                }

效果很好

答案 3 :(得分:2)

您可以使用方法

func setViewControllers(_ viewControllers: [UIViewController], animated: Bool)

以下是解决UIViewController跳过问题的文档(link)。 只需将所有需要的UIViewControllers传递给它(按导航顺序),最后一个将作为当前活动UIViewController(如果它已经不是活动的那个)。

答案 4 :(得分:1)

我的解决方案是保留一个BOOL属性,当你应该跳到第三个并且不跳过时,比如在VC2中声明'shouldSkip',这样如果你在下面准备segue中设置它你可以按照VC2中的那个行事

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if let identifier = segue.identifier {
        switch identifier {
        case "JumpToThirdVCSegue":
            secondvc.shouldSkip=true

            }
        default: break
        }
    }
}

然后在viewDidload VC2中你应该检查这个BOOL,如果它是真的并执行segue,如果不是继续前进 你也可以在没有必要跳过时传递传球

答案 5 :(得分:1)

基于MarkHim的答案,导航回插入的视图控制器时出现黑屏,所以我想出了以下解决方案。

顺便说一句-我想将新的视图控制器直接插入我刚刚设定的视图控制器下,因此是navStack.count - 1而不是navStack - 2

这是我的解决方案:

override func performSegue(withIdentifier identifier: String, sender: Any?) {
    super.performSegue(withIdentifier: identifier, sender: sender)

    if identifier == "JumpToThirdViewControllerSegue",
    let navController = navigationController { // unwrap optional

        // initialize the view controller you want to insert
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let viewControllerToInsert = storyboard.instantiateViewController(
            withIdentifier: "SecondVC") as! SecondViewController

        // set any passed properties
        viewControllerToInsert.passedProperty = propertyToPass

        // create an object using the current navigation stack
        var navStackArray: [UIViewController]! = navController.viewControllers

        // insert the newly initialized view controller into the navStackArray
        navStackArray.insert(viewControllerToInsert, at: navStackArray.count - 1)

        // replace the current navigation stack with the one you just
        // inserted your view controller in to
        navController.setViewControllers(navStackArray, animated: false)
    }
}