10

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()
        }
    }
}
Benjamin Angeria
  • 335
  • 4
  • 14

2 Answers2

3

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()
        }
    }
}
Ofcourse
  • 617
  • 1
  • 7
  • 19
0

Just switch to ScrollView that fixes your problem!

Hamed Hosseini
  • 182
  • 2
  • 13
  • That was suggested if you look at the comments on the question. However, that means you lose default list functionality like "swipe to delete" and reordering. I did end up with that approach in the end nonetheless... – Benjamin Angeria May 02 '22 at 19:52
  • If you ask me it's a bug and for sure Apple won't fix it! switch to scroll view and use custom swipe action. – Hamed Hosseini May 03 '22 at 13:15