SwiftUI问题:关闭ActionSheet/sheet时父视图FooView意外弹出
问题解决:关闭ActionSheet时FooView意外从导航栈弹出
触发原因
- 在iOS 15的SwiftUI中,
NavigationView嵌套TabView的层级结构会引发状态管理冲突。当ActionSheet的isPresented状态从true切换回false时,视图层级的状态刷新会错误传递至NavigationView的导航栈,触发NavigationLink的自动取消逻辑,最终导致FooView被弹出。 - 该问题属于SwiftUI在特定嵌套结构下的状态同步Bug,在iOS 16及后续版本中已被官方修复。
解决方案
方案一:调整视图层级(推荐,符合SwiftUI最佳实践)
将TabView移至NavigationView外部,让每个标签页对应独立的导航栈,隔离状态避免干扰:
@main struct ViewDismissApp: App { var body: some Scene { WindowGroup { TabView { NavigationView { ContentView(title: "Tab 1") } .navigationViewStyle(.stack) .tabItem { Label("Tab1", systemImage: "wifi") } NavigationView { ContentView(title: "Tab 2") } .navigationViewStyle(.stack) .tabItem { Label("Tab2", systemImage: "wrench.adjustable") } } } } }
方案二:手动控制导航栈状态
通过NavigationLink的isActive绑定手动管理导航状态,避免自动触发的弹出逻辑:
- 修改ContentView:
struct ContentView: View { let title: String @State private var isNavigating = false var body: some View { VStack { Button(title) { isNavigating = true } .background( NavigationLink(destination: FooView(isActive: $isNavigating), isActive: $isNavigating) { EmptyView() } ) } } }
- 修改FooView:
struct FooView: View { @Binding var isActive: Bool @State private var showActions = false var body: some View { VStack { Text("Foo View") actionButton() } .navigationBarBackButtonHidden(true) .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button("返回") { isActive = false } } } } private func actionButton() -> some View { Button(action: { showActions = true }) { Image(systemName: "arrow.up.circle") } .actionSheet(isPresented: $showActions) { ActionSheet(title: Text("Actions"), message: nil, buttons: [ .default(Text("Option 1")) { // TODO }, .default(Text("Option 2")) { // TODO }, .cancel() ]) } } }
内容的提问来源于stack exchange,提问作者user1783732
相关产品推荐
相关产品推荐

