Tycho Pandelaar
Tycho Pandelaar

Reputation: 7525

How do I change button backgroundcolor if the button is disabled in swiftUI

I'm trying to create a buttonStyle that has a different background color if the button is disabled.

How do I do that? I've created the code below to react to a variable that I've introduced myself, but is it possible to have it react on the buttons .disabled() state?

My code:

struct MyButtonStyle: ButtonStyle {
    var enabledState = false

    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .foregroundColor(Color.white)
            .padding(10)
            .padding(.horizontal, 20)
            .background(self.enabledState ? Color(UIColor.orange) : Color(UIColor.lightGray))
            .cornerRadius(20)
            .frame(minWidth: 112, idealWidth: 112, maxWidth: .infinity, minHeight: 40, idealHeight: 40, maxHeight: 40, alignment: .center)
            .scaleEffect(configuration.isPressed ? 0.9 : 1.0)
    }
}

struct ContentView: View {
    @State private var buttonEnabled = false

    var body: some View {
        HStack {
            Button("Button") {
                self.buttonEnabled.toggle()
                print("Button pressed")
            }
        }
        .buttonStyle(MyButtonStyle(enabledState: self.buttonEnabled))
    }
}

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

Upvotes: 5

Views: 3232

Answers (2)

Al Priest
Al Priest

Reputation: 323

Again using the Environment.isEnabled but this time using a ViewModifier. This has the advantage that you can use it on other Views, not just Buttons. This implementation reduces the opacity of the button background color so no need for a new style to be injected.

struct MyButtonModifier: ViewModifier {
    @Environment(\.isEnabled) var isEnabled
    let backgroundColor: Color

    func body(content: Content) -> some View {
        content
            .background(backgroundColor.opacity(isEnabled ? 1 : 0.5))
    }
}

Then use it in your code as

Button("foo") {
    // action
}
.modifier(MyButtonModifier(backgroundColor: Color.red))

Upvotes: 2

Asperi
Asperi

Reputation: 257693

To track .disabled there is EnvironmentValues.isEnabled that shows this state. But environment values are applicable only to views and do not work in style.

So the solution is to create custom button that tracks isEnabled and pass it into own style.

Below is a demo of solution approach (MyButtonStyle is not changed). Tested with Xcode 12b.

struct MyButton: View {

    let title: String
    let action: () -> ()

    @Environment(\.isEnabled) var isEnabled // to handle own state !!

    init(_ title: String, action: @escaping () -> ()) {
        self.title = title
        self.action = action
    }

    var body: some View {
        Button(title, action: action)
            .buttonStyle(MyButtonStyle(enabledState: isEnabled))
    }
}

struct ContentView: View {
    @State private var buttonEnabled = true

    var body: some View {
        HStack {
            MyButton("Button") {            // << here !!
                self.buttonEnabled.toggle()
                print("Button pressed")
            }
            .disabled(!buttonEnabled)       // << here !!
        }
    }
}

Upvotes: 5

Related Questions