The issue I have is that the decimalFormatter will not trigger and update the binding unless the textField gets a commit event triggered, i.e. return is tapped.
Thus, I'm looking for how do you manually trigger the textfields commit event?
The formatter code below will take any number and ensure it always has one decimal place (I.E -- 10.5) and also reverts the input back to the previous valid input if letter characters were inserted which is exactly what I want.
import SwiftUI
import Combine
struct StandardRegimen: View {
@State private var totalDose = 6000.0
private var decimalFormatter: NumberFormatter = {
let f = NumberFormatter()
f.isLenient = true
f.numberStyle = .none
f.maximumFractionDigits = 1
f.minimumFractionDigits = 1
f.alwaysShowsDecimalSeparator = true
return f
}()
var body: some View{
return
VStack(alignment:.center,spacing:10){
TextField("?", value:$totalDose, formatter: self.decimalFormatter, onCommit: {
print("COMMITED!");
}).font(.system(size: 25.0))
.textFieldStyle(RoundedBorderTextFieldStyle())
.keyboardType(.decimalPad)
}
}
If you remove the modifier code .keyboardType(.decimalPad)
and press the return key on the keyboard it will trigger the COMMITED message and close the keyboard
However, if you leave the decimal pad modifier on then there is no way to trigger the commit because the decimal pad does not have a return key.
I wrote an answer here on how to get the keyboard to go away by tapping in the open space area (How to hide keyboard when using SwiftUI?)
I have looked into other solutions using binding to a string and using the textfields text
initializer parameter instead of value since this will work correctly with a bound value, but this updates on every keystroke for some very wonky results (I.E -- it's difficult for the user to type and edit mistakes) when I'm looking for it to run the formatter only just after commit, which I want to occur when the user taps to dismiss the keyboard since I will not have the return key option on the decimal keypad.
Any help is appreciated on solutions to this issue.
This may be a little late, but I have come up with a workaround for using other keyboard types with a TextField
: I use the onEditingChanged
event instead of the onCommit
event and check the Bool
value passed into the method. If the value is false, it replicates the behavior of the onCommit
method. Here is your code but formatted to use my method:
import SwiftUI
import Combine
struct StandardRegimen: View {
@State private var totalDose = 6000.0
private var decimalFormatter: NumberFormatter = {
let f = NumberFormatter()
f.isLenient = true
f.numberStyle = .none
f.maximumFractionDigits = 1
f.minimumFractionDigits = 1
f.alwaysShowsDecimalSeparator = true
return f
}()
var body: some View{
VStack(alignment:.center,spacing:10){
TextField("?", value:$totalDose, formatter: self.decimalFormatter, onEditingChanged: { edit in
// Editing has finished
if !edit {
print("COMMITED!");
}
}).font(.system(size: 25.0))
.textFieldStyle(RoundedBorderTextFieldStyle())
.keyboardType(.decimalPad)
}
}
}
This solution should work for all keyboard types (I have only tested regular and num pad).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With