SwiftUI列表单元格内嵌Menu与sheetView冲突异常求助
问题描述
在SwiftUI列表的单元格中添加Menu组件后,点击单元格打开Sheet时出现异常,报错信息如下:
[Presentation] Attempt to present
<TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView>:
0x1620b0800> on
<TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier_>:
0x161811800> (from
<TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier_>:
0x161811800>) which is already presenting
<_UIContextMenuActionsOnlyViewController: 0x16051de40>
冲突原因为Sheet与Menu同时触发展示,导致视图控制器层级冲突。
复现代码
struct Item: Identifiable{ let id: Int let marque: String let reference: String } struct ContentView: View { @State var items = [Item(id: 1, marque: "Schneider", reference: "123333"), Item(id: 2, marque: "Siemens", reference: "1234444"), Item(id: 3, marque: "Beck", reference: "1233"), Item(id: 4, marque: "Aron", reference: "133449")] @State private var selectedItem: Item? var body: some View { List { ForEach(items, id: \.id) { item in HStack { Text(item.marque) Spacer() Menu(content: { Button("Edit") {} Button("Delete") {} }, label: { Image(systemName: "ellipsis.circle") }) } .onTapGesture { self.selectedItem = item } } } .sheet(item: $selectedItem) { item in VStack{ Text(item.marque) Text(item.reference) } } } }
解决方法
方法一:给Menu添加手势优先级
在Menu组件上添加highPriorityGesture(TapGesture()),让Menu优先响应自身点击事件,避免触发父视图的onTapGesture,阻止Sheet与Menu同时弹出。
修改后的代码:
struct Item: Identifiable{ let id: Int let marque: String let reference: String } struct ContentView: View { @State var items = [Item(id: 1, marque: "Schneider", reference: "123333"), Item(id: 2, marque: "Siemens", reference: "1234444"), Item(id: 3, marque: "Beck", reference: "1233"), Item(id: 4, marque: "Aron", reference: "133449")] @State private var selectedItem: Item? var body: some View { List { ForEach(items, id: \.id) { item in HStack { Text(item.marque) Spacer() Menu(content: { Button("Edit") {} Button("Delete") {} }, label: { Image(systemName: "ellipsis.circle") }) .highPriorityGesture(TapGesture()) // 拦截点击事件 } .onTapGesture { self.selectedItem = item } } } .sheet(item: $selectedItem) { item in VStack{ Text(item.marque) Text(item.reference) } } } }
方法二:限制点击手势的作用区域
将onTapGesture从整个HStack移到Text组件上,仅点击文本区域时触发Sheet弹出,点击Menu区域不会触发,从根源避免冲突。
修改后的代码:
struct Item: Identifiable{ let id: Int let marque: String let reference: String } struct ContentView: View { @State var items = [Item(id: 1, marque: "Schneider", reference: "123333"), Item(id: 2, marque: "Siemens", reference: "1234444"), Item(id: 3, marque: "Beck", reference: "1233"), Item(id: 4, marque: "Aron", reference: "133449")] @State private var selectedItem: Item? var body: some View { List { ForEach(items, id: \.id) { item in HStack { Text(item.marque) .onTapGesture { // 仅文本区域触发Sheet self.selectedItem = item } Spacer() Menu(content: { Button("Edit") {} Button("Delete") {} }, label: { Image(systemName: "ellipsis.circle") }) } } } .sheet(item: $selectedItem) { item in VStack{ Text(item.marque) Text(item.reference) } } } }
内容的提问来源于stack exchange,提问作者AdR

