How to change between button styles if a condition is true in SwiftUI?
Asked Answered
D

3

16

I have 2 custom button styles and I want to change the style when I tap the button. I tried this way:

Button(action: {
    self.pressed.toggle()
})
{
    Text("Button")
}.buttonStyle(pressed ? style1() : style2())

But it is not working, it is giving me an error from the VStack that it belongs to:

Unable to infer complex closure return type; add explicit type to disambiguate

If I do something like:

.buttonStyle(style1())

Or

.buttonStyle(style2())

Then the error goes away, so it's not from style1() or style2().

Detrusion answered 25/5, 2020 at 19:0 Comment(0)
M
4

It's swift type-checking violation... I would recommend instead

Button(action: {
    self.pressed.toggle()
})
{
    Text("Button")
}.buttonStyle(Your_style(condition: pressed)) // << put conditional styling inside

See for example solution in Change buttonStyle Modifier based on light or dark mode in SwiftUI

Matabele answered 25/5, 2020 at 19:22 Comment(0)
B
3

You can write an extension on View to apply different modifiers conditionally based on a boolean condition. This can be useful when you want to customize the appearance or behavior of a view based on some state.

First, make sure you have the following extension defined:

extension View {
    @ViewBuilder
    func `if`<TrueContent: View, FalseContent: View>(
        _ condition: Bool,
        if ifTransform: (Self) -> TrueContent,
        else elseTransform: (Self) -> FalseContent
    ) -> some View {
        if condition {
            ifTransform(self)
        } else {
            elseTransform(self)
        }
    }
}

With this extension, you can apply condition-based modifiers to views. Let's take the example of a Button from the question:

Button {
    print("πŸ‘‹πŸ‘‹πŸ‘‹")
} label: {
    Text("Hello World!")
}
.if(vm.status == .subscribed, if: { button in
    button.buttonStyle(TertiaryButton())
}, else: { button in
    button.buttonStyle(SecondaryButton())
})
Brothel answered 8/6, 2023 at 23:23 Comment(1)
Fantastic answer!! I was looking to conditionally apply a button style to a button and the other answers don't work for that. Thank you for this. – Joaquin
H
1

You can create a useful extension like below

extension View {

    func conditionalModifier<M1: ViewModifier, M2: ViewModifier>
        (on condition: Bool, trueCase: M1, falseCase: M2) -> some View {
        Group {
            if condition {
                self.modifier(trueCase)
            } else {
                self.modifier(falseCase)
            }
        }
    }

    func conditionalModifier<M: ViewModifier>
        (on condition: Bool, trueCase: M) -> some View {
        Group {
            if condition {
                self.modifier(trueCase)
            }
        }
    }

}

Usage;

@State var condition = false
var body: some View {
    Text("conditional modifier")
       // Apply style if condition is true, otherwise do nothing
       .conditionalModifier(on: condition, trueCase: Style1())

       // Decision between 2 style
       .conditionalModifier(on: condition, trueCase: Style1(), falseCase: Style2())
}
Harbourage answered 25/5, 2020 at 19:17 Comment(1)
This approach causes SwiftUI to lose track of the view's identity, which can break animation. More info – Inness

© 2022 - 2024 β€” McMap. All rights reserved.