好的,我知道如何使用 UIViewRepresentable 和 Coordinator 包装 UIKit 组件(如 TextField)与 SwiftUI 一起使用。这一切都运作良好。但是,如何以 SwiftUI 的原生方式(即使用修饰符)从 SwiftUI 的角度自定义这些组件?
我有 UITextField 的示例包装器来启用一些额外的委托方法处理。这与将闭包传递给构造函数的本地方法类似。但是我如何使用 SwiftUI 修饰符对这个 UITextField 应用一些样式呢?
struct PasswordField: UIViewRepresentable {
@Binding var text: String
@Binding var isSecured: Bool
let onBeginEditing: () -> Void
let onEndEditing: () -> Void
let onEditingChanged: (Bool) -> Void
let onCommit: () -> Void
init(text: Binding<String>, isSecured : Binding<Bool> = .constant(true),
onBeginEditing: @escaping () -> Void = { },
onEndEditing: @escaping () -> Void = { },
onEditingChanged: @escaping (Bool) -> Void = { _ in },
onCommit: @escaping () -> Void = { }) {
self._text = text
self._isSecured = isSecured
self.onBeginEditing = onBeginEditing
self.onEndEditing = onEndEditing
self.onEditingChanged = onEditingChanged
self.onCommit = onCommit
}
func makeCoordinator() -> Coordinator {
Coordinator(onBeginEditing: onBeginEditing, onEndEditing: onEndEditing, onEditingChanged: onEditingChanged, onCommit: onCommit)
}
func makeUIView(context: UIViewRepresentableContext<PasswordField>) -> UITextField {
let textField = UITextField()
textField.delegate = context.coordinator
textField.addTarget(context, action: #selector(Coordinator.valueChanged(sender:)), for: .valueChanged)
return textField
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<PasswordField>) {
uiView.text = text
uiView.isSecureTextEntry = isSecured
}
}
// MARK: - Coordinator
extension PasswordField {
class Coordinator: NSObject, UITextFieldDelegate {
let onBeginEditing: () -> Void
let onEndEditing: () -> Void
let onEditingChanged: (Bool) -> Void
let onCommit: () -> Void
init(onBeginEditing: @escaping () -> Void,
onEndEditing: @escaping () -> Void,
onEditingChanged: @escaping (Bool) -> Void,
onCommit: @escaping () -> Void) {
self.onBeginEditing = onBeginEditing
self.onEndEditing = onEndEditing
self.onEditingChanged = onEditingChanged
self.onCommit = onCommit
}
@objc func valueChanged(sender: UITextField) {
onEditingChanged(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
onCommit()
return true
}
func textFieldDidBeginEditing(_ textField: UITextField) {
onBeginEditing()
onEditingChanged(true)
}
func textFieldDidEndEditing(_ textField: UITextField) {
onEditingChanged(false)
onEndEditing()
}
}
}
struct PasswordField_Previews: PreviewProvider {
static var previews: some View {
PasswordField(text: .constant("PaSSword"), isSecured: .constant(true))
}
}
现在我想像这样使用它:
PasswordField(text: self.$validator.value, onEditingChanged: { editing in
self.onEditingChanged?(editing)
self.isEdited = true
}, onCommit: {
self.validator.validateField()
self.validator.validateFieldAsync()
})
.font(.custom("AvenirNext-Light", size: 13)) // THIS IS IMPORTANT
.foregroundColor(Color("BodyText")) // THIS IS IMPORTANT
.frame(maxHeight: geometry.size.height)
.offset(x: 0, y: 16)
.padding(10)
好的,我知道我可以在包装器中硬编码这种风格,或者通过构造函数传递它。是的,但这不是 SwiftUI 本地执行此操作的方式。