有没有办法将配置的视图提取到它自己的视图结构中,以便可以应用某些自定义?例如,我在 UI 的几个地方配置了 Button
:
Button(action: {}) {
Text("Some Button Text")
.font(.custom("SomeFont", size: 17.0))
.fontWeight(.bold)
}
.frame(maxWidth: .infinity)
.frame(height: 50.0)
.foregroundColor(.black)
.background(Color("user-profile-action-call1"))
.clipShape(RoundedRectangle(cornerSize: CGSize(width: 10.0, height: 10.0)))
.padding([.leading, .trailing], 20.0)
.padding(.top, 33.0)
我希望能够重复使用它,指定不同的按钮文本和不同的背景颜色。显然,一种方法是创建一个新的 View
,它将 String
和 Color
作为参数/属性,并像这样使用它:
MyButton(title: "Some Button Text", color: Color("user-profile-action-call1"))
但这与 SwiftUI 不一致:
MyButton(title: "Some Button Text")
.background(Color("user-profile-action-call1"))
不幸的是,将背景放置在 .clipShape()
之后会导致填充区域被填充,而不是剪切区域。
有时我也想改变其他方面。但我不确定如何制作真正的自定义视图。
答案 0 :(得分:2)
Grey's answer 在将修饰符组合成自定义修饰符方面是一个很好的方法,但我认为更惯用的 SwiftUI 方式是创建按钮样式。
自定义按钮样式是符合 ButtonStyle
协议的结构体;为了满足协议要求,您需要提供一个 makeBody
函数,该函数将您的样式应用于按钮并返回一个新视图。与任何其他视图或修饰符一样,您可以声明变量来初始化您的结构以使样式可定制。
在您的情况下,我会提取除填充值以外的所有内容:
struct FullWidthButtonStyle: ButtonStyle {
var backgroundColor: Color
func makeBody(configuration: Configuration) -> some View {
configuration.label
.font(.custom("SomeFont", size: 17.0).bold())
.frame(maxWidth: .infinity)
.frame(height: 50.0)
.foregroundColor(.black)
.background(backgroundColor)
.clipShape(RoundedRectangle(cornerSize: CGSize(width: 10.0, height: 10.0)))
}
}
请注意,因为我们将字体应用于 Button
而不是直接应用于 Text
,所以 .fontWeight
修饰符将不起作用 - 但我们应该能够应用 {{ 1}} 到字体声明本身(这需要 Xcode 12.5 - 在早期版本中,您需要切换到 .bold()
才能以这种方式链接字体修饰符)。
然后您可以将样式应用于任何按钮,指定您喜欢的任何背景颜色:
Font.custom...
当谈到 ViewModifier 与 ButtonStyle 时,我认为后者为您提供了一点额外的语义优势:您只想将此样式应用于按钮而不是其他任何东西,但视图修饰符有点过于通用传达这一点。
答案 1 :(得分:0)
自定义视图修饰符可以做到这一点,但您必须记住 SwiftUI 如何创建视图。视图由视图修饰符修改,每个修饰符返回一个新视图。因此,应用修饰符的顺序很重要。
在应用其他视图修改器之后,不可能覆盖视图修改器(如其背景颜色)(如果您想要与更改原始背景完全相同的结果,则不能)。
您可以像这样创建一个新的视图修改器:
struct ButtonModifier: ViewModifier {
var color:Color
func body(content: Content) -> some View {
content
.frame(maxWidth: .infinity)
.frame(height: 50.0)
.foregroundColor(.black)
.background(color)
.clipShape(RoundedRectangle(cornerSize: CGSize(width: 10.0, height: 10.0)))
.padding([.leading, .trailing], 20.0)
.padding(.top, 33.0)
}
}
extension Button {
func roundedWithBackground(_ color:Color) -> some View {
self.modifier(ButtonModifier(color: color))
}
}
这将允许您使用以下“更类似于 SwiftUI”的语法在代码中的其他地方使用您的按钮:
Button(action: {}) {
Text(title)
.font(.custom("SomeFont", size: 17.0))
.fontWeight(.bold)
}.roundedWithBackground(.red)
显然,您可以根据需要向此视图修改器添加更多参数,或者如果您将某些按钮参数包装到它们自己的视图中,则可以这样调用:
MyButton(title: "Some Button Text")
.roundedWithBackground(.red)