英文:
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<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)
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论