Post

Replies

Boosts

Views

Activity

Reply to Can clear first character when using TextField with NumberFormatter and zeroSymbol set to ""
And next convert this string value in places where we need using this extension extension String { var toDoubleWithGroupingSeparator: Double? { guard let groupingSeparator = Locale.current.groupingSeparator, let decimalSeparator = Locale.current.decimalSeparator else { return nil } let valueWithSeperator = self.replacingOccurrences(of: groupingSeparator, with: "") let valueWithFormattedSeperator = valueWithSeperator.replacingOccurrences(of: decimalSeparator, with: ".") return Double(valueWithFormattedSeperator) } }
Feb ’24
Reply to Can clear first character when using TextField with NumberFormatter and zeroSymbol set to ""
Thanks @Frameworks Engineer I've decided to rely on using a String with additional validation after all. It seems to me that it should be possible with a double because that's how it needs to be converted and checked to ensure that the string is properly formatted. The important thing is that it works, so here's my imperfect code. extension Formatter { static let numberFormatter: NumberFormatter = { let formatter = NumberFormatter() formatter.currencyCode = "GBP" formatter.currencySymbol = "" formatter.minimumFractionDigits = 2 formatter.maximumFractionDigits = 2 formatter.numberStyle = .currency return formatter }() } struct HomeView: View { @FocusState private var isFocused: Bool @State var value: String = "" var body: some View { VStack { TextField("0.0", text: $value) .focused($isFocused) .border(.red) .keyboardType(.decimalPad) .onChange(of: isFocused) { newValue in guard newValue == false else { return } guard let doubleValue = Double(value) else { return } value = Formatter.numberFormatter.string(from: NSNumber(floatLiteral: doubleValue)) ?? "0.0" } .onReceive(Just(value), perform: { newValue in if isFocused == false { return } let validator = InputValidator() guard let validated = validator.validate(newValue: newValue) else { return } if newValue != validated { value = validated } }) .toolbar { ToolbarItemGroup(placement: .keyboard) { if isFocused { Spacer() Button("Done") { isFocused = false } } } } } } } extension HomeView { struct InputValidator { func validate(newValue: String) -> String? { guard let decimalSeparator: Character = Locale.current.decimalSeparator?.first else { return nil } let maxFraction = 2 let filtered = newValue.filter { $0.isNumber || $0 == decimalSeparator } if let fractionIndex = filtered.firstIndex(of: decimalSeparator) { let distance = filtered.distance( from: filtered.startIndex, to: fractionIndex ) let lastIndex = min( distance + maxFraction, filtered.count - 1 ) let arrFiltered = Array(filtered) let decimal = String(arrFiltered[0 ... distance]) let fraction = String(arrFiltered[distance ... lastIndex].filter({ $0.isNumber })) return decimal + fraction } return filtered } } }
Feb ’24