SwiftUI中关闭Sheet后如何跳转至新视图?
问题分析
你的核心问题在于把导航逻辑放在了Sheet内部的NavigationStack中——Sheet作为模态弹窗,它的导航栈和父视图的导航栈相互独立。当Sheet关闭时,内部的NavigationStack会被销毁,onDisappear里的导航指令无法生效;如果不移除关闭代码,Sheet先关闭,内部导航栈直接消失,自然没有任何反应。
解决方案
正确的做法是将导航控制权交还给呈现Sheet的父视图,通过绑定值让Sheet通知父视图“需要开启新游戏”,由父视图负责关闭Sheet并触发导航。
修改后的Sheet代码
import SwiftUI struct GameEndCustomSheet: View { @Environment(\.dismiss) private var dismiss // 替换旧的presentationMode API @Binding var shouldStartNewGame: Bool // 绑定父视图状态,传递开启新游戏的信号 var body: some View { VStack { Text("Game Ended") Button(action: { dismiss() // 先关闭Sheet shouldStartNewGame = true // 通知父视图触发新游戏导航 }) { Text("New Game") } } } } struct GameEndCustomSheet_Previews: PreviewProvider { static var previews: some View { GameEndCustomSheet(shouldStartNewGame: .constant(false)) } }
父视图实现(负责呈现Sheet与处理导航)
假设你的父视图是当前游戏页面,需要这样配置:
struct GameView: View { @State private var showEndSheet = false @State private var navigateToNewGame = false var body: some View { NavigationStack { // 这里是当前游戏的内容视图 Text("Current Game View") .toolbar { Button("End Game") { showEndSheet = true } } .sheet(isPresented: $showEndSheet) { GameEndCustomSheet(shouldStartNewGame: $navigateToNewGame) } .navigationDestination(isPresented: $navigateToNewGame) { ContentView() // 新游戏视图 } } } }
关键修改说明
- 弃用旧的
presentationMode,改用SwiftUI 3.0+的@Environment(\.dismiss)API,写法更简洁规范。 - 通过
@Binding实现Sheet与父视图的状态通信,让Sheet仅负责传递“开启新游戏”的信号,导航逻辑交给父视图处理。 - 父视图在自己的NavigationStack中配置
navigationDestination,确保新游戏视图加载在正确的导航层级中,避免出现“新视图在Sheet内部打开”的问题。
内容的提问来源于stack exchange,提问作者ObliviousOre
相关产品推荐
相关产品推荐

