SwiftUI проверяет ввод в текстовые поля - PullRequest
3 голосов
/ 07 апреля 2020

Я пытаюсь проверить пользовательский ввод в TextField, удалив определенные символы с помощью регулярного выражения. К сожалению, у меня проблемы с методом didSet text var, вызывающим себя рекурсивно.

import SwiftUI
import Combine

class TextValidator: ObservableObject {

    @Published var text = "" {
        didSet {
            print("didSet")
            text = text.replacingOccurrences(
                of: "\\W", with: "", options: .regularExpression
            ) // `\W` is an escape sequence that matches non-word characters.
        }
    }

}


struct ContentView: View {

    @ObservedObject var textValidator = TextValidator()

    var body: some View {
        TextField("Type Here", text: $textValidator.text)
            .padding(.horizontal, 20.0)
            .textFieldStyle(RoundedBorderTextFieldStyle())

    }
}

В swift docs (см. Структуру AudioChannel) Apple предоставляет пример, в котором свойство переназначается в своем собственном методе didSet, и явно отмечает, что это не вызвать метод didSet для повторного вызова. Я провел некоторое тестирование на детской площадке и подтвердил это поведение. Однако, кажется, что все работает по-разному, когда я использую переменные ObservableObject и Published.

Как я могу предотвратить рекурсивный вызов метода didSet?

Я попробовал примеры в этом посте , но ни один из них не сработал. С тех пор Apple могла что-то изменить, так что этот пост НЕ является его копией.

Кроме того, возвращение текста к oldValue в методе didSet при обнаружении недопустимых символов будет означать, что если пользователь вставляет текст, тогда весь текст будет удален, в отличие от удаления только недопустимых символов. Так что эта опция не будет работать.

Ответы [ 2 ]

4 голосов
/ 07 апреля 2020

Попробуйте проверить, что вы хотите, в методе TextField onRecive, например:

class TextValidator: ObservableObject {

    @Published var text = ""

}

struct ContentView: View {

    @ObservedObject var textValidator = TextValidator()
    var body: some View {
        TextField("Type Here", text: $textValidator.text)
            .padding(.horizontal, 20.0)
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .onReceive(Just(textValidator.text)) { newValue in
                let value = newValue.replacingOccurrences(
                    of: "\\W", with: "", options: .regularExpression)
                if value != newValue {
                    self.textValidator.text = value
                }
                print(newValue)
        }
    }
}
1 голос
/ 07 апреля 2020

Здесь возможен подход с использованием прокси-привязки, который также позволяет разделять логи модели просмотра и просмотра c

class TextValidator: ObservableObject {

    @Published var text = ""

    func validate(_ value: String) -> String {
        value.replacingOccurrences(
                of: "\\W", with: "", options: .regularExpression
            )
    }
}


struct ContentView: View {

    @ObservedObject var textValidator = TextValidator()

    var body: some View {
        let validatingText = Binding<String>(
                get: { self.textValidator.text },
                set: { self.textValidator.text = self.textValidator.validate($0) }
                )
        return TextField("Type Here", text: validatingText)
            .padding(.horizontal, 20.0)
            .textFieldStyle(RoundedBorderTextFieldStyle())

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...