SwiftUI 将 ViewModifier 作为参数传递

Gil*_*roy 7 swift swiftui

我正在创建一个TextField由多个装饰视图组成的自定义视图。我希望能够TextField使用仅适用于该子视图的视图修饰符(例如键盘、大写等)设置内部。

我认为最好的方法是传递一个可选ViewModifier参数并使用它,如下所示:

struct MySuperTextField: View {
    var vm: ViewModifier?

    var body: some View {
         TextField(...)
           .modifier( vm ?? EmptyModifier() )
         // ... more views here
    }
}
Run Code Online (Sandbox Code Playgroud)

associatedType由于in ,这不起作用ViewModifier。唉,也没有AnyViewModifier这样的东西(而且我不知道如何制作一个有效的)。

有人设法做这样的事情吗?我在网上搜索找不到任何东西。

一个例子是

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
   }
}
Run Code Online (Sandbox Code Playgroud)

然后将它们与我一起使用,MySuperTextField如下所示:

VStack {
    MySuperTextField("Last Name", $lastName, vm: LastNameModifier())

    MySuperTextField("Email", $email, vm: EmailModifier())
}
Run Code Online (Sandbox Code Playgroud)

paw*_*222 8

如果我理解正确,你可以让你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)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以传递一些 ViewModifier作为参数:

struct ContentView: View {
    @State private var text: String = "Test"

    var body: some View {
        MySuperTextField("Last Name", text: $text, vm: LastNameModifier())
    }
}
Run Code Online (Sandbox Code Playgroud)

vm如果您需要一种在创建时跳过参数的方法MySuperTextField

MySuperTextField("Last Name", text: $text)
Run Code Online (Sandbox Code Playgroud)

您可以创建一个扩展:

extension MySuperTextField where V == EmptyModifier {
    init(_ placeholder: String, text: Binding<String>) {
        self.placeholder = placeholder
        self._text = text
        self.vm = EmptyModifier()
    }
}
Run Code Online (Sandbox Code Playgroud)