繁体   English   中英

SwiftUI 将 ViewModifier 作为参数传递

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM