Связывание Swift и SwiftUI из строки TextField с опубликованным необязательным свойством Integer модели - PullRequest
3 голосов
/ 06 февраля 2020

Я новичок в Swift и SwiftUI и имею модель с необязательным @Published intValue и представлением с TextField, где его свойство text / string имеет двухстороннюю привязку к intValue модели. Необходимо убедиться, что допустимая запись текста в виде строки преобразуется в допустимое целое число для модели. Каков рекомендуемый подход для обработки этого в SwiftUI? Код похож на ниже ...

//Model
class AppModel:ObservedObject {
 @Published
 var intValue: Int? = 5
}

//View
@ObservedObject
 var appModel = AppModel.shared

TextField("", text: $appModel.intValue)
                    .keyboardType(.numberPad)

Обновлен пример кода ...

///////////
import SwiftUI

class Model: ObservableObject {
    static var shared: Model = Model()

    @Published
    var number: Int = 0

    init(){}

}

struct ContentView: View {
    var body: some View {
        TextFieldFormatter()
    }
}

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


struct TextFieldFormatter: View {
    @ObservedObject
    var model: Model = Model.shared

    @State private var number: Int = 0


    let formatter: NumberFormatter = {
        let numFormatter = NumberFormatter()
        numFormatter.numberStyle = .none
        return numFormatter
    }()

    var body: some View {
        VStack {
            Text("State").onTapGesture {
                self.endEditing()
            }
            TextField("int", value: $number, formatter: formatter).keyboardType(.numberPad)
            Text("Echo: \(number)")
            Text("Observable")
            TextField("int", value: $model.number, formatter: formatter).keyboardType(.numberPad)
            Text("Echo: \(model.number)")
        }
    }
}

struct TextFieldFormatter_Previews: PreviewProvider {
    static var previews: some View {
        TextFieldFormatter()
    }
}

extension View {
    func endEditing() {
        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to:nil, from:nil, for:nil)
    }
}

Ответы [ 2 ]

2 голосов
/ 06 февраля 2020

Вы можете создать пользовательский Binding для передачи в TextField.

Вот как построить Binding<String> (что нужно TextField):

var string = ""

let myBinding = Binding(get: { string }) {
    string = $0
}

Первым аргументом конструктора Binding является метод получения. Это закрытие должно возвращать значение нужного типа.

Второй аргумент - установщик. Это замыкание, которое принимает новое значение и что-то делает с ним (обычно устанавливает другое значение).

Итак, если вы хотите создать Binding<String> для передачи в TextField, который получает / устанавливает appModel.intValue, вы можете создать Binding<String> и передать его в TextField следующим образом:

TextField("", text: .init(
    get: { self.appModel.intValue.map(String.init) ?? "" },
    set: { self.appModel.intValue = Int($0) }
))
.keyboardType(.numberPad)
1 голос
/ 06 февраля 2020

SwiftUI TextField имеет несколько конструкторов. Один из них принимает параметр Formatter.

https://developer.apple.com/documentation/swiftui/textfield

import SwiftUI

struct TextFieldFormatter: View {
    @ObservedObject var model: Model = Model.shared

    let formatter: NumberFormatter = {
        let numFormatter = NumberFormatter()
        numFormatter.numberStyle = .none
        return numFormatter
    }()

    var body: some View {
        VStack {
            Text("State").onTapGesture {
                self.endEditing()
            }
            TextField("int", value: $model.number, formatter: formatter).keyboardType(.numberPad)
            Text("Echo: \(model.number)")
            Text("Observable")
            TextField("int", value: $model.number, formatter: formatter).keyboardType(.numberPad)
            Text("Echo: \(model.number)")
        }
    }
}

struct TextFieldFormatter_Previews: PreviewProvider {
    static var previews: some View {
        TextFieldFormatter()
    }
}

Также, если вы пытаетесь отключить экран с помощью onTapGesture, который вы можете рассмотреть.

добавление:

   @State var disabled: Bool = false

и изменение:

       Form {
            Text("Disable").onTapGesture {
                //self.endEditing()
                self.disabled = true
            }
            TextField("int", value: $model.number, formatter: formatter).keyboardType(.numberPad)
            Text("Echo: \(model.number)")
            Text("Observable")
            TextField("int", value: $model.number, formatter: formatter).keyboardType(.numberPad)
            Text("Echo: \(model.number)")
        }.disabled($disabled.wrappedValue)

Предоставление обратной связи, пока пользователь печатает, можно сделать несколькими различными способами, но пользовательский UITextView в UIViewRepresentable класс кажется наиболее распространенным.

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