iOS
SwiftUI
Incorrect/Unexpected Behavior
iOS 17.4 Seed 3 (21E5200d)
On device
- Run the given code.
- Try typing some numbers, and see the binded value update.
- Delete the numbers until the field is empty. The value is correctly set to
nil
. - Try typing some numbers again, but this time the binded value won't update.
- I would correctly expect the binded value to be set to
nil
when empty, but I would also expect the input to work just as normal after.
Demo | Workaround |
---|---|
AppleFeedback/FB13705327/demo.swift
Lines 1 to 30 in 013618a
import SwiftUI | |
struct ContentView: View { | |
private static let formatter: NumberFormatter = { | |
let formatter = NumberFormatter() | |
formatter.numberStyle = .decimal | |
formatter.usesGroupingSeparator = false | |
return formatter | |
}() | |
@State private var value: Double? = 3 | |
var body: some View { | |
VStack { | |
TextField("Value", value: $value, formatter: Self.formatter) | |
.textFieldStyle(.roundedBorder) | |
.keyboardType(.decimalPad) | |
if let value { | |
Text("Value = \(value)") | |
} else { | |
Text("Value doesn't exist") | |
} | |
} | |
} | |
} | |
#Preview { | |
ContentView() | |
} |
AppleFeedback/FB13705327/workaround.swift
Lines 1 to 65 in 013618a
import SwiftUI | |
struct ContentView: View { | |
private static let formatter: NumberFormatter = { | |
let formatter = NumberFormatter() | |
formatter.numberStyle = .decimal | |
formatter.usesGroupingSeparator = false | |
return formatter | |
}() | |
@FocusState private var focused: Bool | |
@State private var value: Double? = 3 | |
@State private var valueString = Self.doubleToString(3) | |
var body: some View { | |
VStack { | |
TextField("Value", text: valueBinding()) | |
.textFieldStyle(.roundedBorder) | |
.keyboardType(.decimalPad) | |
.focused($focused) | |
if let value { | |
Text("Value = \(value)") | |
} else { | |
Text("Value doesn't exist") | |
} | |
} | |
.onChange(of: focused) { | |
if !focused { | |
valueString = value.map(Self.doubleToString) ?? "" | |
} | |
} | |
} | |
private func valueBinding() -> Binding<String> { | |
Binding( | |
get: { | |
valueString | |
}, | |
set: { new in | |
if new.isEmpty { | |
value = nil | |
valueString = "" | |
} else if let newValue = Double(new) { | |
value = newValue | |
valueString = Self.doubleToString(newValue) | |
// May be needed in the case that it is set more than once | |
if new.hasSuffix(Self.formatter.decimalSeparator) { | |
valueString.append(Self.formatter.decimalSeparator) | |
} | |
} | |
} | |
) | |
} | |
private static func doubleToString(_ value: Double) -> String { | |
let number = NSNumber(value: value) | |
return Self.formatter.string(from: number)! | |
} | |
} | |
#Preview { | |
ContentView() | |
} |