Search code examples
iosswiftswiftuibindingnumber-formatting

How to bridge from Binding<Float> to Binding<String> using an Extension in SwiftUI?


Context

I have an Extension of Binding limited to Float which converts it into a String for usage with the SwiftUI TextField. However, I encountered two odd behaviours while not being able to identify the causing issues:

  1. When entering more than 4 digits, e.g. 12345, the TextField empties

  2. When entering a decimal separator (e.g. "." in the US), the TextField empties


Code

public extension Binding where Value == Float {
    var adapter: Binding<String> {
        Binding<String>(
            get: {
                guard self.wrappedValue != -1 else { return "" }
                
                let formatter = NumberFormatter()
                formatter.locale = Locale.current
                formatter.numberStyle = .decimal
                
                return formatter.string(from: NSNumber(value: self.wrappedValue)) ?? ""
            },
            set: {
                let formatter = NumberFormatter()
                formatter.locale = Locale.current
                formatter.numberStyle = .decimal
                
                self.wrappedValue = formatter.number(from: $0)?.floatValue ?? -1
            }
        )
    }
}

Question

  • What causes these errors and how can I achieve my goal of bridging from Binding<Float> to Binding<String>?

Solution

  • Don't reinvent the wheel, instead use the new formatting style

    @State private var value: Float = 0
    
    var body: some View {
        //...
        TextField("Value", value: $value, format: .number)
        //...
    }