[英]SwiftUI passing ViewModifier as parameter
我正在创建一个由多个装饰视图组成的自定义TextField
视图。 我希望能够使用仅适用于该子视图的视图修饰符(例如键盘、大写字母等)设置内部TextField
。
我认为最好的方法是传入一个可选的ViewModifier
参数并像这样使用它,而不是为每一个创建属性:
struct MySuperTextField: View {
var vm: ViewModifier?
var body: some View {
TextField(...)
.modifier( vm ?? EmptyModifier() )
// ... more views here
}
}
由于ViewModifier
中的associatedType
,这不起作用。 唉,也没有AnyViewModifier之类的东西(我不知道如何制作一个有效的东西)。
有人设法做这样的事情吗? 我在搜索 web 时找不到任何东西。
一个例子是
struct LastNameModifier: ViewModifier {
func body(content: Content) -> some View {
content
.autocapitalization(.words)
.textContentType(.familyName)
.backgroundColor(.green)
// ... anything else specific to names
}
}
struct EmailModifier: ViewModifier {
func body(content: Content) -> some View {
content
.keyboardType(.emailAddress)
.textContentType(.emailAddress)
.backgroundColor(.yellow)
// ... anything else specific to emails
}
}
然后将它们与我的MySuperTextField
一起使用,如下所示:
VStack {
MySuperTextField("Last Name", $lastName, vm: LastNameModifier())
MySuperTextField("Email", $email, vm: EmailModifier())
}
如果我理解正确,您可以让您的MySuperTextField
接受一个通用参数:
struct MySuperTextField<V>: View where V: ViewModifier {
private let placeholder: String
@Binding private var text: String
private let vm: V
init(_ placeholder: String, text: Binding<String>, vm: V) {
self.placeholder = placeholder
self._text = text
self.vm = vm
}
var body: some View {
TextField(placeholder, text: $text)
.modifier(vm)
}
}
然后,您可以传递一些 ViewModifier作为参数:
struct ContentView: View {
@State private var text: String = "Test"
var body: some View {
MySuperTextField("Last Name", text: $text, vm: LastNameModifier())
}
}
如果您需要在创建MySuperTextField
时跳过vm
参数的方法:
MySuperTextField("Last Name", text: $text)
你可以创建一个扩展:
extension MySuperTextField where V == EmptyModifier {
init(_ placeholder: String, text: Binding<String>) {
self.placeholder = placeholder
self._text = text
self.vm = EmptyModifier()
}
}
因为ViewModifier
有一个关联类型,您不能将其用作实例变量,但我建议您另一种使用方式:
MySuperTextField
不必维护ViewModifier
类型的实例。
struct MySuperTextField: View {
@State var textValue = ""
var body: some View {
TextField("", text: $textValue)
}
}
对于符合ViewModifier
协议的每个结构,您都创建一个扩展:
extension MySuperTextField {
func lastNameModifier() -> some View {
modifier(LastNameModifier())
}
func emailModifier() -> some View {
modifier(EmailModifier())
}
}
你可以这样使用它:
struct ContentView : View {
var body: some View {
VStack {
MySuperTextField(textValue: "Last Name")
.lastNameModifier()
MySuperTextField(textValue: "Email")
.emailModifier()
}
}
}
将 ViewModifier 设置为结构并在视图上调用它。 您只需要具体说明类型,例如我使用的这个 buttonStyle 修饰符:
struct PurchaseButtonStyle: ButtonStyle {
let geometry: GeometryProxy
func makeBody(configuration: Configuration) -> some View {
configuration.label
.frame(minWidth: 0, idealWidth: 300, maxWidth: .infinity)
.padding(.all, geometry.size.height / 30)
.foregroundColor(.black)
.background(.orange)
.cornerRadius(30)
}
}
用途是:
Button(...)
.buttonStyle(PurchaseButtonStyle(geometry: Geometry))
你只需要把它写成特定的修饰符。 我之所以使用它,是因为它在我正在开发的应用程序中很方便。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.