Эффективный способ моделирования данных для SwiftUI - PullRequest
0 голосов
/ 01 мая 2020

Я изучаю SwiftUI + Combine с демонстрационным приложением BP Management.

На домашнем экране есть возможность считывать значения bp (systolicBP, diastolicBP, пульс и вес). Кнопка «Далее» активна только тогда, когда все 4 поля заполнены. элемент управления должен перейти к следующему текстовому полю при вводе правильного ввода. (ввод действителен, когда он попадает в диапазон, указанный местозаполнителем - см. изображение ниже)

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

Предположим, что перечисления будут лучшей моделью, поэтому я продолжил как

enum SBPInput: CaseIterable {
//name is a Text to indicate the specific row
    typealias Field = (name: String, placeholder: String)

    case spb, dbp, pulse, weight, note, date
    var field: Field {
        switch self {
        case .dbp: return ("DBP", "40-250")
        case .spb: return ("SBP", "50-300")
        case .pulse: return ("Pulse", "40-400")
        case .weight: return ("Weight", "30-350")
        case .note: return ("Note", "")
        case .date: return ("", Date().description)
        }
    }

// Here I am getting it wrong, - I can't bind a read only property
    var value: CurrentValueSubject<String, Never> {
        switch self {
        case .date:
            return CurrentValueSubject<String, Never>(Date().description)
        case .spb:
            return CurrentValueSubject<String, Never>("")
        case .dbp:
            return CurrentValueSubject<String, Never>("")
        case .pulse:
            return CurrentValueSubject<String, Never>("")
        case .weight:
            return CurrentValueSubject<String, Never>("70")
        case .note:
            return CurrentValueSubject<String, Never>("")
        }
    }
}
class HomeViewModel: ObservableObject {

    @Published var aFieldsisEmpty: Bool = true
    var cancellable: AnyCancellable?
    var dataSoure = BPInput.allCases

    init() {

        var bpPublishers = (0...3).map{ BPInput.allCases[$0].value }
        //If a field is empty, we need to disable "Next" button
        cancellable = Publishers.CombineLatest4(bpPublishers[0], bpPublishers[1], bpPublishers[2], bpPublishers[3]).map { $0.isEmpty || $1.isEmpty || $2.isEmpty || $3.isEmpty }.assign(to: \.aFieldsisEmpty, on: self)
    }
}

Идея состоит в том, чтобы создать HStacks для каждого datasorce (sbp, dbp , пульс, вес), чтобы выглядеть так HomeScreen

struct HomeScreen: View {
    @ObservedObject var viewModel = HomeViewModel()
    var body: some View {
        VStack {
            ForEach(Range(0...3)) { index -> BPField in
                BPField(input: self.$viewModel.dataSoure[index])
            }
            Button("Next", action: {
                print("Take to the Detail screen")
            }).disabled(self.viewModel.aFieldsisEmpty)
        }.padding()
    }
}

struct BPField: View {
    @Binding var input: BPInput
    var body: some View {
        //implicit HStack
        Text(input.field.name)
        BPTextField(text: $input.value, placeHolder: input.field.name)//Error:- Cannot assign to property: 'value' is a get-only property
        // input.value being read only I can't bind it. How to modify my model now so that I can bind it here?

    }
}

И мой пользовательский TextField

struct BPTextField: View {
    let keyboardType: UIKeyboardType = .numberPad
    var style: some TextFieldStyle = RoundedBorderTextFieldStyle()
    var text: Binding<String>
    let placeHolder: String
    //    var onEdingChanged: (Bool) -> Void
    //    var onCommit: () -> ()
    var background: some View = Color.white
    var foregroundColor: Color = .black
    var font: Font = .system(size: 14)
    var body: some View {
        TextField(placeHolder, text: text)
            .background(background)
            .foregroundColor(foregroundColor)
            .textFieldStyle(style)
    }
}

1 Ответ

0 голосов
/ 01 мая 2020

ваших проблем нет, о чем вам говорит SwiftUI.

, но вы должны сначала скомпилировать "небольшие части" своего кода и упростить его, чтобы компилятор сообщал вам о реальных ошибках.

один здесь:

BPTextField(text: self.$viewModel.dataSoure[index].value, placeHolder: viewModel.dataSoure[index].field.placeholder)

и ошибка:

Невозможно добавить значение типа 'Binding <[BPInput]>' с аргументом типа WritableKeyPath <_, _> '

и, конечно, вы забыли о себе ....

...