Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Button in SwiftUI List

SwiftUI Custom Button in List

I'm trying to create a custom button in a SwiftUI List. I want it to have a blue background with white text, and importantly, to remain blue and go to 50% opacity when pressed, not the default grey.

I tried using a custom ButtonStyle, but when I do so, the tappable area of the button is reduced to just the label itself. If I tap any other part of the cell, the colour doesn't change. If I remove the ButtonStyle, tapping anywhere on the cell works

How can I fix this so that I get my custom colours, including the colour when tapped, but the whole cell is still tappable?

import SwiftUI

struct BlueButtonStyle: ButtonStyle {

  func makeBody(configuration: Self.Configuration) -> some View {
    configuration.label
        .font(.headline)
        .foregroundColor(configuration.isPressed ? Color.white.opacity(0.5) : Color.white)
        .listRowBackground(configuration.isPressed ? Color.blue.opacity(0.5) : Color.blue)
  }
}

struct ExampleView: View {

    var body: some View {
        NavigationView {
            List {
                Section {
                    Text("Info")
                }

                Section {
                    Button(action: {print("pressed")})
                    {
                        HStack {
                            Spacer()
                            Text("Save")
                            Spacer()
                        }

                    }.buttonStyle(BlueButtonStyle())
                }
            }
            .listStyle(GroupedListStyle())
            .environment(\.horizontalSizeClass, .regular)
            .navigationBarTitle(Text("Title"))
        }
    }
}

struct ExampleView_Previews: PreviewProvider {
    static var previews: some View {
        ExampleView()
    }
}
like image 319
Peter Davison-Reiber Avatar asked Apr 02 '20 15:04

Peter Davison-Reiber


People also ask

How do I make a button in SwiftUI?

SwiftUI's button is similar to UIButton , except it's more flexible in terms of what content it shows and it uses a closure for its action rather than the old target/action system. To create a button with a string title you would start with code like this: Button("Button title") { print("Button tapped!") }

How do I add a floating button in SwiftUI?

First, we create a new SwiftUI Single View App in Xcode. Then we add a new File-New-File to our project and create a new SwiftUI View. We call this FloatingMenu. In this view, we will implement the floating action button with its corresponding menu.


1 Answers

In standard variant List intercepts and handles content area of tap detection, in your custom style it is defined, by default, by opaque area, which is only text in your case, so corrected style is

demo

Update for: Xcode 13.3 / iOS 15.4

It looks like Apple broken something, because listRowBackground now works only inside List itself, no subview, which is senseless from generic concept of SwiftUI.

Updated solution with same behavior as on demo

Original for: Xcode 11.4 / iOS 13.4

struct BlueButtonStyle: ButtonStyle {

  func makeBody(configuration: Self.Configuration) -> some View {
    configuration.label
        .font(.headline)
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
        .contentShape(Rectangle())
        .foregroundColor(configuration.isPressed ? Color.white.opacity(0.5) : Color.white)
        .listRowBackground(configuration.isPressed ? Color.blue.opacity(0.5) : Color.blue)
  }
}

and usage, just

Button(action: {print("pressed")})
{
    Text("Save")
}.buttonStyle(BlueButtonStyle())

and even

Button("Save") { print("pressed") }
    .buttonStyle(BlueButtonStyle())
like image 123
Asperi Avatar answered Oct 20 '22 17:10

Asperi