MacOS Sonoma 14.6 MacCatalyst中三级Sheet弹窗立即消失问题求助
Mac Catalyst(Sonoma 14.6)多层Sheet弹出后自动消失问题及修复方案
问题现象
在MacOS Sonoma 14.6的Mac Catalyst环境中,若第一层Sheet是作为NavigationStack内部视图的修饰符添加(而非直接修饰NavigationStack本身),弹出第三层Sheet后会立即自动消失。该问题不会出现在MacOS 13.6的Mac Catalyst、iOS 16.4及iOS 17.6环境中。
由于实际应用中每个NavigationStack需要承载多个Sheet,因此原本采用overlay包裹EmptyView的方式实现Sheet挂载,现在需要找到兼容iOS>16及MacOS>14.6的Mac Catalyst环境的正确写法。
问题复现代码
import SwiftUI @main struct TestSheetsApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { @State var popup1Item = false var body: some View { NavigationStack { Button("显示弹窗1") { popup1Item = true } // 这段代码会导致第三层弹窗弹出后立即消失 .overlay( EmptyView() .sheet(isPresented: $popup1Item) { Popup1() } ) } // 这段代码能让第三层弹窗正常显示 /* .overlay( EmptyView() .sheet(isPresented: $popup1Item) { Popup1() } ) */ } } struct Popup2: View { @State var showPopup3 = false var body: some View { NavigationStack { Button("显示弹窗3") { showPopup3 = true } } .overlay( EmptyView() .sheet(isPresented: $showPopup3) { Text("弹窗3") } ) } } struct Popup1: View { @State var popup2Item = false var body: some View { NavigationStack { Button("显示弹窗2") { popup2Item = true } .overlay( EmptyView() .sheet(isPresented: $popup2Item) { Popup2() } ) } } }
修复方案
核心问题在于Sonoma 14.6的Mac Catalyst对Sheet的视图层级处理有变化,将Sheet修饰符挂载到NavigationStack内部视图上时,会导致多层弹窗的状态管理异常。
正确的做法是统一将Sheet的overlay修饰符挂载到NavigationStack的外部,而非内部的Button或其他视图上。这样可以保证Sheet的状态不受NavigationStack内部视图刷新的影响,同时依然满足一个NavigationStack对应多个Sheet的需求。
修改后的代码
import SwiftUI @main struct TestSheetsApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { @State var popup1Item = false var body: some View { NavigationStack { Button("显示弹窗1") { popup1Item = true } } // 将Sheet的overlay移到NavigationStack外部 .overlay( EmptyView() .sheet(isPresented: $popup1Item) { Popup1() } ) } } struct Popup2: View { @State var showPopup3 = false var body: some View { NavigationStack { Button("显示弹窗3") { showPopup3 = true } } .overlay( EmptyView() .sheet(isPresented: $showPopup3) { Text("弹窗3") } ) } } struct Popup1: View { @State var popup2Item = false var body: some View { NavigationStack { Button("显示弹窗2") { popup2Item = true } } // 将Sheet的overlay移到NavigationStack外部 .overlay( EmptyView() .sheet(isPresented: $popup2Item) { Popup2() } ) } }
说明
- 所有Sheet的
overlay都直接修饰对应的NavigationStack,而非内部的子视图 - 该写法兼容iOS>16及MacOS>14.6的Mac Catalyst环境,同时保留了一个NavigationStack对应多个Sheet的扩展性(可在同一个NavigationStack的外部叠加多个
overlay挂载不同Sheet)
内容的提问来源于stack exchange,提问作者John Cashew
相关产品推荐
相关产品推荐

