Swiftui list row with multiple buttons?

Can one get multiple buttons to work when included in a List row?


This problem can be seen in the completed version of the Apple tutorial. There, the HikeDetail or HikeView each work when previewed by itself - one can select different graphs by the Elevation, Heart Rate, and Pace buttons. However, this view does not work properly when it is included in the ProfileSummary List(). When tapping on one of the buttons, the view collapses. This is because all buttons are activated, rather than just the one tapped.


It seems that List() is deciding that if it sees a button in the row, it will change multiple behaviors:

1) The button is no longer tinted - if one uses a simple button, it is tinted outside of a List. (Note: The tutorial is playing with colors to show blue/gray - even in the List view).

2) The button no longer flashes when pressed/tapped.

3) A tap in the row activates the actions of all buttons included in that row.


I can understand that this might be the desired behavior to make the simplest row - when only one button. But it is frustrating when one can no longer depend on the look or actions that one has built up at lower levels of the code, just because one now includes it in a List table.


One partial workaround is to not use Button(), but rather add a tap or gesture to the view one has built up. But then one doesn’t get the helpful flash animation available in a button.


Looking particularly for a way to get items 2 and 3 above to work together. Can work around item 1 like was done in the tutorial - but might be nice if this worked, too.

Post not yet marked as solved Up vote post of anorskog Down vote post of anorskog
24k views

Replies

I'm having the same problem with two Buttons inside an HStack. This condition was noticed after the update to macOS Catalina, Version 10.15.4. Did not notice this problem before the update. I did try the ".buttonStyle(DefaultButtonStyle()" solution given in a Post below, but it did not solve my problem.

After a little more investigation it looks like a .onTapGesture Instance Method might be a better practice than Button Generic Structure.


import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            HStack {
                Text("Left Button")
                    .onTapGesture {
                        print("Left Button Tapped")
                }
                Spacer()
                Text("Right Button")
                    .onTapGesture {
                        print("Right Button Tapped")
                }
            }
        }
    }
}


For a few different reasons this looks like it could be more reliable than using Buttons?

Thanks @724QD58FHA  that fixed it for me
I was able to get this working with the latest iOS 14 beta. It appears .buttonStyle(PlainButtonStyle()) stops the List Row itself being selected and .foregroundColor(Color.accentColor) to get the button accent colour back.

import SwiftUI

struct ContentView: View {

    @State var inputString = ["1", "2", "3", "4", "5"]

    init() {

        // Didn't appear to need this thank goodness!
        //
//        UITableView.appearance().allowsSelection = false
//        UITableViewCell.appearance().selectionStyle = .none
    }

    var body: some View {

        Text("List Item with selectable Buttons").padding()

        List {

            ForEach(0..<5) { idx in

                HStack {

        Text("Title")

                    TextField("Enter new value",text: $inputString[idx])

                    Spacer()

                    Button(action: {

                        print("Button did select 1 at idx \(idx)")
                    }) {

                        Text("Selectable 1")
                    }.buttonStyle(PlainButtonStyle())
                    .foregroundColor(Color.accentColor)

                    Button(action: {

                        print("Button did select 2 at idx \(idx)")
                    }) {

                        Text("Selectable 2")
                    }.buttonStyle(PlainButtonStyle())
                    .foregroundColor(Color.accentColor)

                }
            }
        }
    }
}



struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }

}
  • This worked for me as well. I hope everyone who's had his time wasted by this bug has filed a report.

Add a Comment

@eleanorsp8 Your solution works and should be marked as a solution. It seems like the default button style inside a List/Form adds its action to the the row’s on tap gesture listener behind the scenes and it makes sense in most cases — see Settings.app / General / Shut down for example. Plain button styles seems to prevent this behavior, and imho is a cleaner solution compare Text/Image components with .onTapGesture modifiers, from the accessibility and future-proof standpoint. Thanks!

simply add

.buttonStyle(BorderlessButtonStyle())

to all the buttons in an HStack etc or on a list row and they will only fire individually and only when individually tapped.

This worked for me:

.buttonStyle(PlainButtonStyle())