'How to apply a context menu to buttons in a SwiftUI list row?

When I'm long-pressing on a button in list row, all of context menus for all buttons are shown. It looks like the whole list row is selected. How can I make it so that the context menu is shown only for the pressed button?

I've seen this question which is somewhat related, and tried BorderlessButtonStyle(). It enables the indiviual buttons in the row to be clickable, but it doesn't solve the context menu problem. I've also tried using .onTapGesture() instead of Button(), but that didn't work either.

In the example below I'm expecting to see only Action for button 1 when long-pressing on Button 1 - but Action for button 2 is also shown.

enter image description here

struct ContentView: View {
    var body: some View {
        List {
            ForEach((1..<3), content: { _ in
                ListButton()
            })
        }
    }
}

struct ListButton: View {
    var body: some View {
        HStack {
            Spacer()

            Button("Button 1") { }
                .buttonStyle(BorderlessButtonStyle())
                .contextMenu(menuItems: {
                    Text("Action for button 1")
                })

            Spacer()

            Button("Button 2") { }
                .buttonStyle(BorderlessButtonStyle())
                .contextMenu(menuItems: {
                    Text("Action for button 2")
                })

            Spacer()
        }
    }
}


Solution 1:[1]

You could use Menu instead of ContextMenu and use the label of the menu to display your button; as alternative solution.

However, to give the buttons gesture more priority than the row itself, you can add .highPriorityGesture(TapGesture()) to the end of you buttons.

You can achieve what you want by using Menu instead of ContextMenu like this:

struct ListButton: View {
    var body: some View {
        HStack {
            Spacer()

            Button("Button 1") { }
                .buttonStyle(BorderlessButtonStyle())
                .contextMenu(menuItems: {
                    Text("Action for button 1")
                })

            Spacer()
            // Here I used menu instead of the button 2
            Menu {
                Text("Action for button 2")
            } label: {
                Button("Button 2") { }
                    .buttonStyle(BorderlessButtonStyle())

            }.highPriorityGesture(TapGesture())

            Spacer()
        }
    }
}

Solution 2:[2]

Just switch to ScrollView that fixes your problem!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Hamed Hosseini