SwiftUI:带有 onTapGesture 的列表单元格内的菜单触发手势

Sti*_*tch 8 swiftui swiftui-list

List在 iOS14.3 (Xcode12.3) 上有一个 SwiftUI,在它的单元格内我想Menu在用户点击按钮时弹出一个窗口。此外,这些单元格还有一个onTapGesture问题是,按下菜单按钮时也会触发此手势。

例子:

List {
    HStack {
        Text("Cell content")
        Spacer()
        // Triggers also onTapGesture of cell
        Menu(content: {
            Button(action: { }) {
                Text("Menu Item 1")
                Image(systemName: "command")
            }
            Button(action: { }) {
                Text("Menu Item 2")
                Image(systemName: "option")
            }
            Button(action: { }) {
                Text("Menu Item 3")
                Image(systemName: "shift")
            }
        }) {
            Image(systemName: "ellipsis")
                .imageScale(.large)
                .padding()
        }
    }
    .background(Color(.systemBackground))
    .onTapGesture {
        print("Cell tapped")
    }
}
Run Code Online (Sandbox Code Playgroud)

如果点击省略号图像,菜单将打开,但也会"Cell tapped"打印到控制台。这对我来说是一个问题,因为在我的现实世界示例中,我在点击手势中折叠单元格,当然我不希望用户按下菜单按钮时发生这种情况。

我发现,当我长按按钮时,不会触发手势。但在我看来,这是不可接受的用户体验,我花了一段时间才自己发现这一点。

Menu我还注意到,当我用常规替换 时Button,按下时不会触发单元格手势(仅使用BorderlessButtonStylePlainButtonStyle,否则他根本不活动)。但我不知道如何从它的操作中打开菜单。

List {
    HStack {
        Text("Cell content")
        Spacer()
        // Does not trigger cells onTapGesture, but how to open Menu from action?
        Button(action: { print("Button tapped") }) {
            Image(systemName: "ellipsis")
                .imageScale(.large)
                .padding()
        }
        .buttonStyle(BorderlessButtonStyle())
    }
    .background(Color(.systemBackground))
    .onTapGesture {
        print("Cell tapped")
    }
}
Run Code Online (Sandbox Code Playgroud)

paw*_*222 12

或者,您可以覆盖 Menu onTapGesture

struct ContentView: View {
    var body: some View {
        List {
            HStack {
                Text("Cell content")
                Spacer()
                Menu(content: {
                    Button(action: {}) {
                        Text("Menu Item 1")
                        Image(systemName: "command")
                    }
                    Button(action: {}) {
                        Text("Menu Item 2")
                        Image(systemName: "option")
                    }
                    Button(action: {}) {
                        Text("Menu Item 3")
                        Image(systemName: "shift")
                    }
                }) {
                    Image(systemName: "ellipsis")
                        .imageScale(.large)
                        .padding()
                }
                .onTapGesture {} // override here
            }
            .contentShape(Rectangle())
            .onTapGesture {
                print("Cell tapped")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

此外,无需使用.background(Color(.systemBackground))敲击垫片。这并不是很灵活——如果你想改变背景颜色怎么办?

您可以使用contentShape

.contentShape(Rectangle())
Run Code Online (Sandbox Code Playgroud)