47

I've got two buttons in a list, tho when tapping, the full area of the list item is highlighted. Is there a way to separate the two buttons?

In this case I've got an Action button and an Info button:

enter image description here

I found this question, tho no direct solution.

Here's the code:

var body: some View {
    HStack {
        Text(control.name)
        Spacer()
        Button(action: {
            print("action")
        }) {
            Text("Action")
            }
            .frame(width: 250 - 10)
            .padding(5)
            .background(Color(white: 0.9))
            .cornerRadius(10)
            .frame(width: 250)
        Group {
            Button(action: {
                print("action")
            }) {
                Image(systemName: "info.circle")
                    .foregroundColor(.accentColor)
            }
        }
    }
}
Matteo Pacini
  • 21,796
  • 7
  • 67
  • 74
Heestand XYZ
  • 1,993
  • 3
  • 19
  • 40
  • I don't think there's a way to do that yet - as a temporary workaround, you could replace the list with a `ForEach` of `HStack`, where `HStack` will be your row content. Be aware that the styling won't be the same - `List` is more refined in that sense. – Matteo Pacini Jun 13 '19 at 08:41
  • 1
    Possible duplicate of [SwiftUI - Multiple Buttons in a List row](https://stackoverflow.com/questions/56561064/swiftui-multiple-buttons-in-a-list-row) – Fogmeister Jun 13 '19 at 08:47
  • @Fogmeister That solution uses .tapAction, a working solution, tho the highlight states are lost.. – Heestand XYZ Jun 17 '19 at 11:27
  • @Fogmeister I combined it with one button and one tapAction of the info image, it's a working solution for now. – Heestand XYZ Jun 17 '19 at 11:29
  • try .buttonStyle(BorderlessButtonStyle()) – Sham Dhiman May 19 '21 at 07:31

5 Answers5

93

Set the button style to something different from the default, e.g., BorderlessButtonStyle()

struct Test: View {
  var body: some View {
    NavigationView {
      List {
        ForEach([
          "Line 1",
          "Line 2",
        ], id: \.self) {
          item in
          HStack {
            Text("\(item)")
            Spacer()
            Button(action: { print("\(item) 1")}) {
              Text("Button 1")
            }
            Button(action: { print("\(item) 2")}) {
              Text("Button 2")
            }
          }
        }
        .onDelete { _ in }
        .buttonStyle(BorderlessButtonStyle())
      }
      .navigationBarItems(trailing: EditButton())
    }
    .accentColor(.red)
  }
}
Anton
  • 1,655
  • 15
  • 16
13

I struggled with this issue for a while. Apple has made Button kind of special in SwiftUI. It can change depending on the context it's used. That is why we see this weird functionality when a Button is inside a List.

Fortunately, there are other ways using .onTapGesture. Try out the code below.

var body: some View {
    HStack {
        Text(control.name)
        Spacer()
        Text("Action")
            .frame(width: 250 - 10)
            .padding(5)
            .background(Color(white: 0.9))
            .cornerRadius(10)
            .frame(width: 250)
            .onTapGesture {
                print("action1")
            }
    
        Image(systemName: "info.circle")
            .foregroundColor(.accentColor)
            .onTapGesture {
                print("action2")
            }
    }
}
Jake
  • 13,097
  • 9
  • 44
  • 73
4

On Xcode 12.5 I've had the same issue in SwiftUI, the full area of the list item being highlighted when tapped.

.buttonStyle(BorderlessButtonStyle()) does the job, and now the two custom button can be tapped separately on the list item.

kewika
  • 47
  • 1
  • 5
2

For anyone having a similar problem with the latest SwiftUI (Xcode 11.2) and multiple Buttons in a HStack, I got my problem solved only after converting all buttons in the HStack to Images and adding the .onTapGesture handler.

The problem in my case was that tapping on one button triggered all other buttons in the HStack. Only after I converted all buttons to images did they stop interfering with each other.

Of course, if your buttons don't have an image, you can use Text instead.

  • 1
    Had an issue with buttons in a list row as well where tapping anywhere in the list would trigger one of the button actions, but adding a `.buttonStyle(PlainButtonStyle())` to each button helped restrict the tap zone to the actual buttons themselves. – UberJason Jan 07 '20 at 18:46
  • Had the same problem in an HStack. Text works but of course you don't get the default styling. Weird bug... assume this will be fixed in next version of Xcode. thx – Jason Jun 13 '20 at 13:57
-7

You can add padding or try adding Spacer

Add Padding

HStack {
        Text("Button")
        Spacer()
        Button(action: {
            print("action")
        }) {
            Text("Action")
            }
            .frame(width: 250 - 10)
            .padding(5)
            .background(Color(white: 0.9))
            .cornerRadius(10)
            .frame(width: 250)
        Group {
            Button(action: {
                print("action")
            }) {
                Image(systemName: "info.circle")
                    .foregroundColor(.accentColor)
            }
            .padding(15)
        }
    }

Add Spacer

HStack {
        Text("Button")
        Spacer()
        Button(action: {
            print("action")
        }) {
            Text("Action")
            }
            .frame(width: 250 - 10)
            .padding(5)
            .background(Color(white: 0.9))
            .cornerRadius(10)
            .frame(width: 250)
        Spacer()
        Group {
            Button(action: {
                print("action")
            }) {
                Image(systemName: "info.circle")
                    .foregroundColor(.accentColor)
            }
        }
    }

barbsan
  • 3,418
  • 11
  • 21
  • 28
Vivek
  • 1