Создание настраиваемого SwiftUI View для адаптации к встроенным модификаторам - PullRequest
0 голосов
/ 06 марта 2020

Я пытаюсь написать свой собственный BetterTextField вид для SwiftUI, так как встроенный TextField отсутствует в нескольких областях. А именно, я хочу поддержать отложенное связывание (обновление значения привязки только при нахождении фокуса, вместо принудительного выполнения redr aws после каждого нажатия клавиши), программный c контроль фокусировки / ответчика и некоторые другие функции UIKit UITextField, которые SwiftUI не хватает.

Итак, я создал пользовательский UIViewRepresentable с координатором в качестве UITextFieldDelegate, и он работает нормально. Однако для паритета с другими представлениями мне бы очень хотелось, чтобы мое настраиваемое текстовое поле адаптировалось к некоторым существующим модификаторам SwiftUI.

Например:

// Here's my content view
struct ContentView: View {
    var body: some View {
        BetterTextField("Username", text: $username)
            // I want to adapt the view to this modifier
            .textFieldStyle(RoundedBorderTextFieldStyle())
    }
}

// Here's my (simplified) custom text field view
struct BetterTextField: UIViewRepresentable {
    var title: String
    @Binding var text: String

    init(_ title: String, text: Binding<String>) {
        self.title = title
        self._text = text
    }

    func makeUIView(context: Context) -> UITextField {
        let textField = UITextField()
        textField.placeholder = title
        return textField
    }

    func updateUIView(_ view: UITextField, context: Context) {
        view.text = text

        // How can I check for the .textFieldStyle() modifier here and set the corresponding UIKit style accordingly?
        view.borderStyle = .roundedRect
    }
}

Как говорится в комментарии, как Могу ли я адаптировать свойство borderStyle моего UITextField для соответствия модификатору View?

И в целом, как можно проверить наличие модификаторов и вернуть соответствующий стиль пользовательского представления (например, .bold() перевод на атрибутивный текст, возможно)?

Ответы [ 2 ]

1 голос
/ 06 марта 2020
Модификаторы

View - это просто функции, которые просто возвращают снова some View, поэтому вы можете реализовать поддержку любого модификатора, соответствующего любому протоколу, который вы сочтете подходящим для вашего пользовательского типа. Как ваш элемент управления будет работать с каждым реализованным модификатором, зависит от вас.

Ниже приведена простая демонстрационная поддержка модификатора textFieldStyle, которая делает ваш ContentView рендер BetterTextField в соответствии с назначением в зависимости от добавленного модификатора стиля прямоугольной формы. или удалены.

struct BetterTextField: UIViewRepresentable {
    var title: String
    @Binding var text: String

    private let textField = UITextField()

    init(_ title: String, text: Binding<String>) {
        self.title = title
        self._text = text
    }

    func makeUIView(context: Context) -> UITextField {
        textField.placeholder = title
        return textField
    }

    func updateUIView(_ view: UITextField, context: Context) {
        view.text = text
    }
}

extension BetterTextField {
    func textFieldStyle<S>(_ style: S) -> some View where S : TextFieldStyle {
        if style is RoundedBorderTextFieldStyle {
            self.textField.borderStyle = .roundedRect
        }
        return self
    }
}
0 голосов
/ 06 марта 2020
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension View {

    /// Sets the style for `TextField` within the environment of `self`.
    public func textFieldStyle<S>(_ style: S) -> some View where S : TextFieldStyle

}

см. Примечание

Устанавливает стиль для TextField в среде self

UIViewRepresentable наследуется от View, но не имеет любой TextField внутри 'self'

.bold, .itali c ... являются модификаторами для шрифта, а не для универсального c представления. Допустим, скажем,

Image("image001").italic()

также не работает.

О разборке см. Оболочка отклоненного свойства

О привязке с задержкой см.

/// Creates an instance with a `Text` label generated from a localized title
    /// string.
    ///
    /// - Parameters:
    ///     - titleKey: The key for the localized title of `self`, describing
    ///       its purpose.
    ///     - text: The text to be displayed and edited.
    ///     - onEditingChanged: An `Action` that will be called when the user
    ///     begins editing `text` and after the user finishes editing `text`,
    ///     passing a `Bool` indicating whether `self` is currently being edited
    ///     or not.
    ///     - onCommit: The action to perform when the user performs an action
    ///     (usually the return key) while the `TextField` has focus.
    public init(_ titleKey: LocalizedStringKey, text: Binding<String>, onEditingChanged: @escaping (Bool) -> Void = { _ in }, onCommit: @escaping () -> Void = {})

ПРИМЕР "отложенного" связывания

import SwiftUI
struct MyTextField<S>: View  where S: StringProtocol {
    let label: S
    @State private var __text = ""
    @Binding var text: String
    var body: some View {
        TextField(label, text: $__text, onEditingChanged: { (e) in

        }) {
            self.text = self.__text
        }
    }
}

struct ContentView: View {
    @State var text = " "
    var body: some View {
        VStack {
            MyTextField(label: "label", text: $text).textFieldStyle(RoundedBorderTextFieldStyle())
            Text(text)
        }.padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

enter image description here

Если вам нужен другой шрифт и .bold, используйте

MyTextField(label: "label", text: $text).textFieldStyle(RoundedBorderTextFieldStyle()).font(Font.title.bold())

или

MyTextField(label: "label", text: $text).font(Font.title.bold()).textFieldStyle(RoundedBorderTextFieldStyle())
...