除了扩展Button以外,是否还有其他替代方法来自定义ButtonStyle?

huangapple go评论72阅读模式
英文:

Is there other alternative other than extending Button for ButtonStyle?

问题

我的目标是拥有条件按钮样式。但是,.buttonStyle(selected : .bordered : .borderedProminent) 无法使用。

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
英文:

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

答案1

得分: 3

注意,.bordered.borderedProminent 不符合 ButtonStyle。它们符合 PrimitiveButtonStyle

因此,解决这个问题的一种方法是引入一个 PrimitiveButtonStyle,它包装了你想要选择的两种样式。为了以一种通用、可重用的方式实现它,可以将它定义为对这两种样式的泛型包装:

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)
        }
    }
}

然后像这样使用它:

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)
        }
    }
}
英文:

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&lt;Left, Right&gt; {
    case left(Left)
    case right(Right)
}

extension Either: PrimitiveButtonStyle where Left: PrimitiveButtonStyle, Right: PrimitiveButtonStyle {
    func makeBody(configuration: Configuration) -&gt; 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)
        }
    }
}

huangapple
  • 本文由 发表于 2023年7月23日 23:46:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76749118.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定