【问题标题】:SwifUI using UIKit components by implementing UIViewRepresentableSwiftUI 通过实现 UIViewRepresentable 来使用 UIKit 组件
【发布时间】:2019-12-17 09:15:20
【问题描述】:

好的,我知道如何使用 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 本地执行此操作的方式。

【问题讨论】:

    标签: uikit swiftui uiviewrepresentable


    【解决方案1】:

    您需要实现自己的自定义修饰符。请参阅 ViewModifier 协议的文档,尽管 SwiftUI 文档仍然很薄。

    但是,您不必实现自己的 TextField 来处理密码输入,因为 SwiftUI 现在原生支持您想要的:SecureField。

    【讨论】:

    • 仅链接答案不被视为良好做法。请看stackoverflow.com/help/how-to-answer
    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
    • @SuitBoyApps,感谢您指出。我已删除链接,但目前无法提供更完整的答案。
    猜你喜欢
    • 2022-08-05
    • 2020-06-21
    • 2019-12-05
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    相关资源
    最近更新 更多