Problem with TextFields and decimals iOS17

After upgrading to iOS 17 I am struggling to get decimals working in my app - here is a sample code: for clarity I provide a complete "working" sample (I am pulling data from a back-end server using json, etc - all of that is working ok, it's the UI issue - see below):

Model

import Foundation

struct TestFloat: Encodable {
    var testFloatNumber: Float = 0
}

Observable Class

import Foundation

class TestFloatViewModel: ObservableObject {
    @Published var testFloat = TestFloat()
}

View

struct TestFloatView: View {
    
    @ObservedObject var testFloatVM: TestFloatViewModel

    let formatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        return formatter
    }()
    
    var body: some View {
        VStack {
            HStack {
                Text("Enter Float Number")
                Spacer()
            }
            Spacer()
                .frame(height: 2.0)
            HStack {
                TextField("Enter Float Number", value: $testFloatVM.testFloat.testFloatNumber, formatter: formatter)
                    .keyboardType(.decimalPad)
                    .textFieldStyle(.roundedBorder)
            }
        }
    }
}

This is working on a device with iOS16; however when run on device with iOS17:

  • you can enter maximum four digits?
  • using backspace you can delete all numbers apart of the first one
  • you cannot enter the decimal (.) at all even though decimal keyboard is provided

Any help is greatly appreciated.

I should add that this is not working when the Textfield is in .sheet or .fullScreenCover

I should actually clarify - this is not working when textField is in .sheet on .fullScreenCover. The code looks like so:

Main View

import SwiftUI

struct TestFloatView: View {
    @ObservedObject var testFloatVM: TestFloatViewModel
    
    @State private var showAddLoad = false
    
    var body: some View {
        VStack {
            HStack {
                Button {
                    showAddLoad = true
                    
                } label: {
                    Text("Text")
                }
            }
        }
        .fullScreenCover(isPresented: $showAddLoad, content: {
            NavigationView {
                EnterFloatView(testFloatVM: testFloatVM)
                    .navigationBarItems(
                        
                        leading: Button(action: {
                            showAddLoad = false
                        }, label: {
                            Text("Cancel")
                                .foregroundColor(Color("AccentRed"))
                        }),
                        
                        trailing: Button(action: {
                            showAddLoad = false
                            
                        }, label: {
                            Text("Save")
                                .fontWeight(.bold)
                        })
                    )
                    .navigationBarTitleDisplayMode(.inline)
            }
        })
    }
}

Sheet View

import SwiftUI

struct EnterFloatView: View {
    @ObservedObject var testFloatVM: TestFloatViewModel

    let formatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        return formatter
    }()
    
    var body: some View {
        VStack {
            HStack {
                Text("Enter Float Number")
                Spacer()
            }
            Spacer()
                .frame(height: 2.0)
            HStack {
                TextField("Enter Float Number", value: $testFloatVM.testFloat.testFloatNumber, formatter: formatter)
                    .keyboardType(.decimalPad)
                    .textFieldStyle(.roundedBorder)
            }
        }
    }
}

If text field is placed in main view like in my original post, then it works OK.

I have the exact same issue in my app. I found out that it works with a state variable inside the view. I didn't have any luck binding to a variable inside of an observed object. Hence, my workaround relays the value from a state variable to the observed object.

@State private var price: Decimal?

func priceTextField() -> some View {
    let textField = TextField(
        "Price",
        value: $price,
        format: .number
    )
    .keyboardType(.decimalPad)
    .focused($focusedField, equals: .price)
    .onAppear {
        price = model.tx.decimalPrice
    }

    if #available(iOS 17.0, *) {
        return textField.onChange(of: price, initial: false) {
            model.tx.decimalPrice = price
        }
    }

    return textField
}

I also have the same problem with iOS 17. I have a TextField bound to an ObservedObject. If you then enter a comma (in Germany), the system deletes it again. Sometimes you can't edit the value itself. Strangely enough, sometimes it works all of a sudden, but usually it doesn't work.

The only workaround that works for me is to remove the @Published property from a variable like so:

import Foundation

class TestFloatViewModel: ObservableObject {
    @Published var testFloat = TestFloat()
}

This is not ideal because the view is not updated if I need the view to update when this variable is updated (if I don' need this variable to control/impact view updates, then it is less of a problem).

I applied this workaround because I need users to enter the data in a correct format, but I really don't understand why the original code is not working with iOS 17...

Apologies, the code above should read:

import Foundation

class TestFloatViewModel: ObservableObject {
    var testFloat = TestFloat()
}

Looks like iOS 17.1 and 17.2 don't fix the issue either :-(

Did any of you submit a feedback ticket to Apple for this issue? I am also facing issues with TextFields with Decimals in iOS 17

Same issue here (only in Sheets and only on iPad, not iPhone), very bizarre

This is a bug even today, on iOS 18.0.

Problem with TextFields and decimals iOS17
 
 
Q