Skip/Add 导航堆栈中的视图控制器
Skip/Add a View Controller in Navigation Stack
我在导航控制器中嵌入了三个视图控制器。我想从 VC1 转到 VC3,这样在 VC3 中,导航项的后退按钮会将用户定向到 VC2 而不是 VC1。我认为这应该通过在创建 VC3 时 将 VC2 添加到 VC1 和 VC3 之间的导航堆栈 或 跳过第二个视图控制器 来完成.
我试过这个:
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
}
}
}
但我无法让它工作。也许在 View Controller 尚未打开时无法执行 segue?
跳过视图控制器/在导航堆栈中间添加视图控制器的最佳方法是什么?我希望这可以帮助您理解我正在尝试做的事情:
像这样的东西应该可以工作:
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)
}
}
}
编辑:使用 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,以便在实际执行到 VC3 的转接(并且不仅在准备中)时更改导航堆栈。
这假定您要在 VC1 中处理这种特殊的导航逻辑。
我的解决方案是保留一个 BOOL 属性,说明何时应该跳到第三个,什么时候不跳过,比如在 VC2 中声明“shouldSkip”,这样如果你像下面那样在准备转场中设置它,你就可以按照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,如果它是 true 并执行 segue,如果不是就继续
你也可以在不需要那种跳过的时候通过 pass
你可以使用方法
func setViewControllers(_ viewControllers: [UIViewController],
animated: Bool)
这是解决 UIViewController
跳过问题的文档 (link)。
只需将所有需要的 UIViewControllers
传递给它(按导航顺序),最后一个将成为当前活动的 UIViewController
(如果它已经不是活动的)。
if var navstack = navigationController?.viewControllers{
navstack.append(contentsOf: [vc1,vc2])
navigationController?.setViewControllers(navstack, animated: true)
}
效果不错
根据 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)
}
}
我在导航控制器中嵌入了三个视图控制器。我想从 VC1 转到 VC3,这样在 VC3 中,导航项的后退按钮会将用户定向到 VC2 而不是 VC1。我认为这应该通过在创建 VC3 时 将 VC2 添加到 VC1 和 VC3 之间的导航堆栈 或 跳过第二个视图控制器 来完成.
我试过这个:
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
}
}
}
但我无法让它工作。也许在 View Controller 尚未打开时无法执行 segue?
跳过视图控制器/在导航堆栈中间添加视图控制器的最佳方法是什么?我希望这可以帮助您理解我正在尝试做的事情:
像这样的东西应该可以工作:
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)
}
}
}
编辑:使用 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,以便在实际执行到 VC3 的转接(并且不仅在准备中)时更改导航堆栈。 这假定您要在 VC1 中处理这种特殊的导航逻辑。
我的解决方案是保留一个 BOOL 属性,说明何时应该跳到第三个,什么时候不跳过,比如在 VC2 中声明“shouldSkip”,这样如果你像下面那样在准备转场中设置它,你就可以按照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,如果它是 true 并执行 segue,如果不是就继续 你也可以在不需要那种跳过的时候通过 pass
你可以使用方法
func setViewControllers(_ viewControllers: [UIViewController],
animated: Bool)
这是解决 UIViewController
跳过问题的文档 (link)。
只需将所有需要的 UIViewControllers
传递给它(按导航顺序),最后一个将成为当前活动的 UIViewController
(如果它已经不是活动的)。
if var navstack = navigationController?.viewControllers{
navstack.append(contentsOf: [vc1,vc2])
navigationController?.setViewControllers(navstack, animated: true)
}
效果不错
根据 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)
}
}