Keyboard Done Button Failing to Appear About 60% of Time

I am working on an app that saves transaction entries. The user is requested to enter date / time, select local currency, payment type, category, description, and expense amount. When entering the description and entry amount they may tap the Done button above the keyboard to dismiss the keyboard. The problem is that quite commonly the Done button doesn't appear and with the decimal keyboard there is no way to dismiss the keyboard. I would say that the Done button appears only about 30-40% of the time.

In the EntryView structure, I define the @FocusStatus and pass it down to GetDescription(myFocus: myFocus) and GetMoney(myFocus: myFocus). Further down in EntryView under the toolbar I setting up the Done Button operation and resetting myFocus to nil.

In GetMoney I am using the binding var myFocus: FocusState<EntryView.Field?>.Binding.

Finally below the GetMoney TextField("Amount" ... there is the .focused(myFocus, equals: .ckAmt

GetDescription is not much of a problem because the default keyboard has a built in done button (.submitLabel(.done)).

I have Focus / Done operation in four other locations in my app where this works just fine. I need help figuring out why it fails part of the time.

struct EntryView: View {
   
    enum Field: Hashable {
        case ckDsc
        case ckAmt
    }
    @FocusState private var myFocus: Field?
    
    var body: some View {
        
        GeometryReader { g in
            VStack {
                
                Form {
                    GetDate(entryDT: $entryDT)
                    GetCurrency()
                    GetPaymentType(g: g, entryPT: $entryPT)
                    GetCategory(entryCat: $entryCat)
                    GetDescription(g: g, entryDsc: $entryDsc, myFocus: $myFocus)
                    GetMoney(g: g, moneyD: $moneyD, myFocus: $myFocus)
                }
                
            }
            .navigationBarTitleDisplayMode(.inline)
            .toolbarBackground(.visible, for: .navigationBar)
            .toolbarBackground(Color.orange, for: .navigationBar)
            .toolbar(content: {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Done") {
                        myFocus = nil
                    }
                }
                ToolbarItem(placement: .principal) {
                    VStack (alignment: .leading) {
                        
                        HStack {
                            Text("Expense Entry")
                                .font(.title)
                                .bold()
                                .kerning(1.5)
                                .padding(.leading, 10)
                                .frame(maxWidth: .infinity, alignment: .leading)
                            
                            Spacer()
                            
                            Button {
                                myFocus = nil
                                
                                if moneyD != 0.0 {
                                    self.saveButton()   // button pressed
                                }
                                if !zeroEntry {
                                    dismiss()
                                }
                                
                            } label: {
                                Text("Save")
                                    .bold()
                                    .padding(.trailing, 10)
                                    .tint(.blue)
                            }
                            .disabled(moneyD == 0.0)
                            
                        }
                    }
                }
            })
          
        }
    }
    
    // Entry save button has been pressed: save data to swiftdata
    func saveButton() {
   
    }
}


struct GetMoney: View {
    
    var g: GeometryProxy
    @Binding var moneyD: Double?
    var myFocus: FocusState<EntryView.Field?>.Binding
    
    var body: some View {
        
        Section(header: Text("Enter Amount")) {      
                HStack {
                    TextField("Amount", value: $moneyD, format: .number.precision(.fractionLength(0...2)))
                        .focused(myFocus, equals: .ckAmt)
                        .font(.headline)
                        .padding(.vertical, 10)
                        .keyboardType(.decimalPad)
                }
            }
        }
    }
}
Answered by DTS Engineer in 808215022

First I’d suggest that you file a feedback report, please include the code snippet to reproduce the issue and possibly a video of issue if you're able to capture it– If you do so, please share your report ID here for folks to track.

A workaround you might want to consider is falling back to UITextField and using an inputAccessoryView for your done button.

First I’d suggest that you file a feedback report, please include the code snippet to reproduce the issue and possibly a video of issue if you're able to capture it– If you do so, please share your report ID here for folks to track.

A workaround you might want to consider is falling back to UITextField and using an inputAccessoryView for your done button.

Accepted Answer

After considerable review of the Done button operation, I noticed that I could get the button to reappear by selecting another tab and then returning to the expense entry tab.

I added some breakpoints and noticed that some of the state parameters were not getting reset upon saving the data.

Finally, I moved the state parameter reset logic outside the getLocation closure and this appears to have fixed the state parameters for the next entry and the Done button. The weird Done button behavior is no longer occurring!

func saveButton() {

    if moneyD == 0.0 {
        zeroEntry = true

    } else {

        withAnimation {

            // get coordinates and address
            getLocation { addr in
                self.addr = addr

                // address
                if let city = addr.locality {
                    entryLocCity = city
                }

                if let state = addr.administrativeArea {
                    entryLocState = state
                }

                if let countryL = addr.countryL {
                    entryLocCountryL = countryL
                }

                if let countryS = addr.countryS {
                    entryLocCountryS = countryS
                }

                
                guard let moneyD else { return }
                let moneyH = categories.saveCategoryTotal(entryCat: self.entryCat, rate: rate, moneyD: moneyD)

                modelContext.insert(TravelEntries(
                    id: UUID(),
                    entryDate: entryDT,
                    ...
                    entryLocCity: entryLocCity,
                    entryLocState: entryLocState,
                    entryLocCountryS: entryLocCountryS,
                    entryLocCountryL: entryLocCountryL
                ))
                dtTotals.addToDailyTotal(gotDate: entryDT, gotTotal: moneyH)

            }
                        
            // reset parameters for next entry
            self.entryDT = Date()
            self.entryCat = 0
            self.entryPT = 0
            self.entryDsc = ""
            self.moneyD = nil
            
        }
    }

Keyboard Done Button Failing to Appear About 60% of Time
 
 
Q