My goal is to have conditional button style. However, .buttonStyle(selected : .bordered : .borderedProminent)
can't be used.
struct DepartureArrivalView: View {
@Binding var value: String
@Binding var selected: Bool
var body: some View {
VStack(spacing: 0) {
Button {
} label: {
Text(value)
.frame(maxWidth: .infinity, alignment: .leading)
.font(.title)
}
.customButtonStyle(selected)
.padding(16)
}
}
}
extension Button {
@ViewBuilder
func customButtonStyle(_ selected: Bool) -> some View {
switch selected {
case true:
self.buttonStyle(.bordered)
case false:
self.buttonStyle(.borderedProminent)
}
}
}
#if DEBUG
struct DepartureArrivalView_Previews: PreviewProvider {
static var previews: some View {
DepartureArrivalView(value: .constant("A"), selected: .constant(true))
}
}
#endif
Note that .bordered
and .borderedProminent
don't conform to ButtonStyle
. They conform to PrimitiveButtonStyle
.
So, one way to solve this is by introducing a PrimitiveButtonStyle
that wraps the two styles you want to choose from. To do it in a generic, reusable way, make it generic over the two styles:
enum Either<Left, Right> {
case left(Left)
case right(Right)
}
extension Either: PrimitiveButtonStyle where Left: PrimitiveButtonStyle, Right: PrimitiveButtonStyle {
func makeBody(configuration: Configuration) -> some View {
switch self {
case .left(let left):
left.makeBody(configuration: configuration)
case .right(let right):
right.makeBody(configuration: configuration)
}
}
}
Then use it like this:
struct DepartureArrivalView: View {
@Binding var value: String
@Binding var selected: Bool
private var style: some PrimitiveButtonStyle {
return selected ? Either.left(.bordered) : .right(.borderedProminent)
}
var body: some View {
VStack(spacing: 0) {
Button {
} label: {
Text(value)
.frame(maxWidth: .infinity, alignment: .leading)
.font(.title)
}
.buttonStyle(style)
.padding(16)
}
}
}