Как динамически обновлять метки на экране, когда все текстовые поля имеют значения в SwiftUI? - PullRequest
1 голос
/ 02 апреля 2020

Я работаю над приложением, которое позволяет пользователям вводить коэффициенты для ставки, используя 2 отдельных текстовых поля. Например, предположим, что шансы, которые хочет получить пользователь, равны 3/1. Пользователь должен будет ввести 3 в одно поле и 1 в другое.

enter image description here

У меня есть 2 переменные состояния:

  • leftOddsVal
  • rightOddsVal

Вот как я использую их с CustomTextField:

CustomTextfield(text: $leftOddsVal, placeHolder: "Enter text", keyboardType: .numberPad)
CustomTextfield(text: $rightOddsVal, placeHolder: "Enter text", keyboardType: .numberPad)
CustomTextfield(text: $state, placeHolder: "Enter text", keyboardType: .numberPad)

Это код для пользовательского текстового поля:

struct CustomTextfield: UIViewRepresentable {

    @Binding var text : String
    var placeHolder: String
    var keyboardType: UIKeyboardType

    final class Coordinator: NSObject {

        var textField: CustomTextfield

        init(_ textField: CustomTextfield) {
            self.textField = textField
        }

    }

    func makeCoordinator() -> DabbleTextfield.Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> UITextField {

        let textField = UITextField()
        textField.backgroundColor = .white
        textField.placeholder = self.placeHolder
        textField.keyboardType = self.keyboardType

        return textField
    }

    func updateUIView(_ uiView: UITextField, context: Context) {

    }

}

Что я пытаюсь сделать:

Я хочу взять значения каждого поля и написать немного логики c, чтобы выяснить, сколько можно выиграть и проиграть, а затем обновить некоторые текстовые метки на экране. Вместо того, чтобы пользователь отправлял форму прежде, чем он сможет увидеть, что он может выиграть или проиграть, я бы хотел, чтобы ярлыки выигрыша / проигрыша обновлялись автоматически после того, как все поля имеют значения.

Вот как выглядят ярлыки:

enter image description here

Проблема:

  1. Метод делегата textFieldDidEndEditing должен знать, что метод для запуска. Это означает, что мне нужно изменить CustomTextField, чтобы вызвать метод внутри моей viewModel, который будет запускаться. Затем я могу запустить метод расчета выигрыша / проигрыша. Тем не менее, я начинаю чувствовать, как много работы для чего-то такого простого. Это выглядит грязно.

  2. Я не могу получить доступ к значениям текстового поля непосредственно внутри представления. Это было бы просто, если бы я использовал компонент TextField SwiftUI. Тем не менее, я использую компонент UITitxtField UIKit, завернутый в структуру UIRepresentable, как вы можете видеть в моем коде выше.

То, что я пробовал:

У меня есть модель представления, и я попытался передать ее в CustomtextField.

Я просто объявил свою переменную среды следующим образом:

   struct CustomTextfield: UIViewRepresentable {

      @EnvironmentObject var viewModel: EnvironmentObject<AnyObject>
      @Binding var text : String
      var placeHolder: String
      var keyboardType: UIKeyboardType

Я использовал AnyObject, чтобы можно было привести любую модель, которую я передам, в CustomTextField как правильный тип. Я не хочу когда-либо вручную изменять CustomTextField для обслуживания каждой модели, с которой я могу его использовать.

Теперь я использую CustomTextField следующим образом:

   CustomTextfield(viewModel: betViewModel as! EnvironmentObject<BetViewModel>, value: $oddsLeftValue, placeHolder: "Enter text", keyboardType: .numberPad)

И я храню копия TextField в переменной моего ViewModel:

func makeUIView(context: Context) -> UITextField {
    let textField = UITextField()
    if let fieldValue = textField.text {
        self.viewModel.textField = fieldValue
    }

Но я получаю следующую ошибку:

Type 'AnyObject' does not conform to protocol 'ObservableObject'

Я также попытался установить значение связанного текста равным значению textField, но это тоже не сработало.

Я надеюсь, что кто-нибудь может дать мне некоторое представление о том, что я делаю неправильно. Я чувствую, что иду по кругу, и причина этого кроется в попытке повторно использовать компонент UIRepresentable UIKit. Кажется, это ограничивает меня, что приводит к обходным путям, которые кажутся излишними для того, чего я пытаюсь достичь.

Все, что я хочу сделать, - это позволить пользователю вводить свои шансы, ставить и иметь ярлыки выигрыша / проигрыша обновляются динамически, без необходимости нажимать какие-либо кнопки. Все время, будучи в состоянии повторно использовать CustomTextField.

Ждем ваших предложений. Заранее спасибо.

1 Ответ

0 голосов
/ 02 апреля 2020

Приведенное ниже делает ваше пользовательское текстовое поле работоспособным ... для обновления внешней границы, надеюсь, что это было целью такого длинного описания.

Протестировано с Xcode 11.4 / iOS 13.4

Маленький TestCustomTextfield в конце был использован для проверки обновления ярлыка на изменения в CustomTextfield.

struct CustomTextfield: UIViewRepresentable {

    @Binding var text : String
    var placeHolder: String
    var keyboardType: UIKeyboardType

    final class Coordinator: NSObject, UITextFieldDelegate {

        var parent: CustomTextfield

        init(_ parent: CustomTextfield) {
            self.parent = parent
        }

        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            parent.text = textField.text ?? ""
            return true
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> UITextField {

        let textField = UITextField()
        textField.backgroundColor = .white
        textField.placeholder = self.placeHolder
        textField.keyboardType = self.keyboardType
        textField.setContentHuggingPriority(.required, for: .vertical)
        textField.delegate = context.coordinator

        return textField
    }

    func updateUIView(_ uiField: UITextField, context: Context) {
        if let text = textField.text as NSString? {
           parent.text = text.replacingCharacters(in: range, with: string)
        } else {
           parent.text = ""
        }
     }

}

struct TestCustomTextfield: View {
    @State private var value = ""
    var body: some View {
        VStack {
            Text("Label: \(value)")
            CustomTextfield(text: $value, placeHolder: "Your value", keyboardType: .numberPad)
        }
    }
}
...