Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set custom highlighted state of SwiftUI Button

Tags:

swiftui

I have a Button. I want to set custom background color for highlighted state. How can I do it in SwiftUI?

enter image description here

Button(action: signIn) {
    Text("Sign In")
}
.padding(.all)
.background(Color.red)
.cornerRadius(16)
.foregroundColor(.white)
.font(Font.body.bold())
like image 480
subdan Avatar asked Jun 08 '19 19:06

subdan


People also ask

How to change button color in SwiftUI?

To change a button's text color in SwiftUI we need to use . foregroundColor on our text view. In the above code it is almost the same as the simple button, but we used a modifier to change the foregroundColor to green. This needs to be on the Text and not on the Button view.

How do you highlight a button in Swift?

In storyboard choose the UIButton you want to change. In the identity inspector in the right corner there is a filed named "class" there type "HighlightedButton" and press enter. Now your button will change color to red when it is highlighted and back to green when you release the button.

How do I add 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!") }


3 Answers

Updated for SwiftUI beta 5

SwiftUI does actually expose an API for this: ButtonStyle.

struct MyButtonStyle: ButtonStyle {

  func makeBody(configuration: Self.Configuration) -> some View {
    configuration.label
      .padding()
      .foregroundColor(.white)
      .background(configuration.isPressed ? Color.red : Color.blue)
      .cornerRadius(8.0)
  }

}


// To use it
Button(action: {}) {
  Text("Hello World")
}
.buttonStyle(MyButtonStyle())

like image 60
arsenius Avatar answered Oct 25 '22 14:10

arsenius


As far as I can tell, theres no officially supported way to do this as of yet. Here is a little workaround that you can use. This produces the same behavior as in UIKit where tapping a button and dragging your finger off of it will keep the button highlighted.

struct HoverButton<Label>: View where Label: View {

    private let action: () -> ()

    private let label: () -> Label

    init(action: @escaping () -> (), label: @escaping () -> Label) {
        self.action = action
        self.label = label
    }

    @State private var pressed: Bool = false

    var body: some View {
        Button(action: action) {
            label()
                .foregroundColor(pressed ? .red : .blue)
                .gesture(DragGesture(minimumDistance: 0.0)
                    .onChanged { _ in self.pressed = true }
                    .onEnded { _ in self.pressed = false })
        }    
    }
}
like image 24
BlueSpud Avatar answered Oct 25 '22 14:10

BlueSpud


I was looking for a similar functionality and I did it in the following way.

I created a special View struct returning a Button in the style I need, in this struct I added a State property selected. I have a variable named 'table' which is an Int since my buttons a round buttons with numbers on it

struct TableButton: View {
    @State private var selected = false

    var table: Int

    var body: some View {
        Button("\(table)") {
            self.selected.toggle()
        }
        .frame(width: 50, height: 50)
        .background(selected ? Color.blue : Color.red)
        .foregroundColor(.white)
        .clipShape(Circle())
    }
}

Then I use in my content View the code

HStack(spacing: 10) {
  ForEach((1...6), id: \.self) { table in
    TableButton(table: table)
  }
}

This creates an horizontal stack with 6 buttons which color blue when selected and red when deselected.

I am not a experienced developer but just tried all possible ways until I found that this is working for me, hopefully it is useful for others as well.

like image 7
Nico van der Linden Avatar answered Oct 25 '22 14:10

Nico van der Linden