Swift Navigation如何替换ViewController并同时传递参数?
方案1:直接修改导航栈数组(最推荐,无动画异常)
UINavigationController的viewControllers属性为读写属性,官方支持直接修改该数组实现栈内控制器的替换,不会出现先pop再push的动画闪烁问题,同时可以直接传递参数,属于永久替换的标准方案:
// 在当前ViewController中执行替换逻辑 guard let nav = navigationController else { return } // 1. 拿到当前导航栈的所有控制器 var vcStack = nav.viewControllers // 2. 移除当前栈顶的控制器(也就是当前页面) vcStack.removeLast() // 3. 初始化目标ViewController,直接传递参数 let newVC = NewViewController() newVC.params = self.params // 4. 把新控制器加入栈 vcStack.append(newVC) // 5. 应用新的导航栈,可设置是否开启动画 nav.setViewControllers(vcStack, animated: true)
如果你使用Storyboard创建目标VC,可以用instantiateViewController方法初始化:
let newVC = storyboard?.instantiateViewController(withIdentifier: "NewViewController") as! NewViewController newVC.params = self.params
方案2:自定义Segue适配Storyboard开发场景
如果你习惯使用Segue跳转,可以自定义Segue类实现替换逻辑,原有prepare传参逻辑完全不用修改:
- 新建继承自
UIStoryboardSegue的自定义Segue类:
class ReplaceTopSegue: UIStoryboardSegue { override func perform() { guard let nav = source.navigationController else { return } var vcStack = nav.viewControllers vcStack.removeLast() vcStack.append(destination) nav.setViewControllers(vcStack, animated: true) } }
- 在Storyboard中找到你原来的
ToNewViewControllerSegue,将类修改为ReplaceTopSegue,之后你还是可以用原来的代码执行跳转和传参:
// 执行Segue代码不变 performSegue(withIdentifier: "ToNewViewController", sender: self) // prepare传参逻辑也不需要修改 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { let destinationVC = segue.destination as! NewViewController destinationVC.params = params }
关于先pop再push的方案说明
该方案在技术上可以实现,但会出现明显的动画跳跃、闪烁问题,用户体验很差,不建议使用,直接修改导航栈数组是官方认可的标准替换方案。
内容的提问来源于stack exchange,提问作者Punreach Rany
相关产品推荐
相关产品推荐

