在以下代码中,当我使用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()
}
}
答案 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
}