You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI列表单元格内嵌Menu与sheetView冲突异常求助

SwiftUI列表单元格Menu与Sheet冲突解决

问题描述

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 23:30:43