将UITextField集成到SwiftUI中查看更新问题

时间:2019-10-07 12:30:53

标签: uitextfield swiftui

在以下代码中,当我使用CustomTextField更改某些字段的值(并因此更改状态)时,似乎无法获得FORM视图的更新。我认为问题出在CustomTextField和SwiftUI之间,但是我在进行计算时会得到值(如下所示),但是我无法获得更新后的值显示在屏幕上的相关UITextField中。

有人可以发现我的错误吗?任何想法将不胜感激。

非常感谢。

克里斯

struct CustomTextField: UIViewRepresentable {

    var tag:Int = 0
    var placeholder:String?
    var keyboardType:UIKeyboardType?
    var textAlignment:NSTextAlignment?
    @Binding var text: String
    var onChange: (()->Void?)?

    func makeCoordinator() -> Coordinator {
        Coordinator(text: $text, onChange: onChange)
    }

    func makeUIView(context: UIViewRepresentableContext<CustomTextField>) -> UITextField {
        let tmpView           = UITextField()
        tmpView.tag           = tag
        tmpView.delegate      = context.coordinator as UITextFieldDelegate
        tmpView.placeholder   = placeholder
        tmpView.textAlignment = textAlignment ?? .left
        tmpView.keyboardType  = keyboardType ?? .default
        tmpView.addDoneButtonOnKeyboard()
        return tmpView
    }

    func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomTextField>) {
        uiView.setContentHuggingPriority(.defaultHigh, for: .vertical)
        uiView.setContentHuggingPriority(.defaultLow, for: .horizontal)
    }

    class Coordinator : NSObject, UITextFieldDelegate {

        @Binding var text: String
        var onChange:(()->Void?)?

        init(text: Binding<String>, onChange: (()->Void?)?) {
            self._text = text
            self.onChange = onChange

        }

        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            if let currentTag              = textField.tag as Int? {
                if currentTag == 1 {
                    if string.count > 0 /*&& !textField.text!.contains(".")*/ {
                        let tmpCents       = textField.text?.replacingOccurrences(of: ".", with: "") ?? ""
                        let cents          = Int( tmpCents + string) ?? 0
                        if cents == 0 {
                            textField.text = "0.00"
                        } else {
                            let dols       = Float(cents)/Float(100)
                            textField.text = String(format: "%0.2f", dols)
                        }
                        self.text          = textField.text!
                        return false
                    }
                }
            }
            if let currentValue            = textField.text as NSString? {
                let proposedValue          = currentValue.replacingCharacters(in: range, with: string)
                text                       = proposedValue
            }
            return true
        }

        func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
            self.text = textField.text ?? ""
            return true
        }

        func textFieldDidChange(_ textField: UITextField) {
            self.text = textField.text ?? ""
        }

        func textFieldDidEndEditing(_ textField: UITextField) {
            self.onChange?()
            textField.resignFirstResponder()
        }

    }

}

struct DetailView: View {

    @EnvironmentObject var log: GasLog

    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    @State var amount        = ""
    @State var pickedDate    = Date()
    @State var kilometers    = ""
    @State var editingAmount = false
    @State var litres        = ""
    @State var gasPrice      = ""
    @State var showAlert     = false
    @State var errorMessage  = ""
    @State var reloadContent = false

    var dateClosedRange: ClosedRange<Date> {
        let min = Calendar.current.date(byAdding: .day, value: -10, to: Date())!
        let max = Calendar.current.date(byAdding: .day, value: 10, to: Date())!
        return min...max
    }

    var body: some View {
        VStack {
            HStack {
                Text("ADD GAS PURCHASE")
                .font(defaultSectionFont)
            }
            Form {
                DatePicker(selection: $pickedDate, displayedComponents: .date, label: {
                    Text("PURCHASE DATE").font(defaultFormFont)
                } )
                HStack {
                    Text("AMOUNT").font(defaultFormFont)
                    Spacer()
                    CustomTextField(tag: 1,
                                    placeholder: "purchase amount",
                                    keyboardType: .numberPad,
                                    textAlignment: .right,
                                    text: $amount,
                                    onChange: nil)
                }
                HStack {
                    Text("LITRES").font(defaultFormFont)
                    Spacer()
                    CustomTextField(tag: 1, placeholder: "litres purchased", keyboardType: .numberPad,
                                    textAlignment: .right, text: $litres, onChange: self.calcValues)
                 }
                HStack {
                    Text("FUEL PRICE").font(defaultFormFont)
                    Spacer()
                    CustomTextField(tag: 1, placeholder: "fuel price", keyboardType: .numberPad,
                                    textAlignment: .right, text: $gasPrice, onChange: self.calcValues)
                 }
                HStack {
                    Text("KILOMETERS ON CAR").font(defaultFormFont)
                    Spacer()
                    CustomTextField(tag: 0, placeholder: "kilometers", keyboardType: .numberPad,
                                    textAlignment: .right, text: $kilometers, onChange: nil)
                }

            }

            HStack {
                Spacer()
                Button(action: {
                    self.cancelRecord()
                }, label: {
                    Image(systemName: "return")
                })
                .padding()
                .overlay(
                    RoundedRectangle(cornerRadius: CGFloat(8.0))
                        .stroke(Color.gray, lineWidth: CGFloat(2.0))
                    )
                Spacer()
                Button(action: {
                    self.commitRecord()
                }, label: {
                    Image(systemName: "plus.square")
                })
                .padding()
                .overlay(
                    RoundedRectangle(cornerRadius: CGFloat(8.0))
                        .stroke(Color.gray, lineWidth: CGFloat(2.0))
                    )
                Spacer()
            }
            .padding()
            .background(toolbarBackgroundColor)
        }.alert(isPresented: $showAlert) {
            Alert(title: Text("Error"), message: Text(self.errorMessage))
        }
    }

    func calcValues() -> Void {
        if !self.amount.isEmpty {
            switch (!self.gasPrice.isEmpty, !self.litres.isEmpty) {
            case (true, false) :
                self.litres    = String(format: "%0.2f", Float(self.amount)! / Float(self.gasPrice)!)
                self.reloadContent = true
            case (false, true) :
                self.gasPrice    = String(format: "%0.2f", Float(self.amount)! / Float(self.litres)!)
                self.reloadContent = true
            default :
                self.reloadContent = false
            }
        }
    }

    func commitRecord() {
        let log = GasLog.shared()
        if self.amount.isEmpty || Float(self.amount) == 0.0 {
            errorMessage = "Value of AMOUNT is invalid. Please re-enter."
            showAlert    = true
        } else {
            self.dismiss()
            log.addLogItem(date:        self.pickedDate,
                           amount:      (self.amount.isEmpty     ? 0.00  : Float(self.amount)!),
                           kilometers:  (self.kilometers.isEmpty ? nil   : Int(self.kilometers)),
                           gasPrice:    (self.gasPrice.isEmpty   ? nil   : Float(self.gasPrice)),
                           litres:      (self.litres.isEmpty     ? nil   : Float(self.litres)))
        }
    }

    func cancelRecord() {
        self.dismiss()
    }

    func dismiss() {
        self.presentationMode.wrappedValue.dismiss()
    }
}

1 个答案:

答案 0 :(得分:2)

uiView.text = text添加到updateUIView

func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomTextField>) {
            uiView.setContentHuggingPriority(.defaultHigh, for: .vertical)
            uiView.setContentHuggingPriority(.defaultLow, for: .horizontal)
            uiView.text = text // add this
}