BLACK FRIDAY: Save 50% on all my Swift books and bundles! >>

SOLVED: Problems with FocusState after showing an alert

Forums > SwiftUI

I have a problem with the OK button I add to the keyboard via the toolbar. The input via the keyboard is to be terminated via the OK button. This also works until I present an alert to inform the user of an incorrect entry. After that, the OK button no longer works, or sometimes it is no longer visible after I have confirmed the alert. In addition, I only have this behaviour when I present the view for input via a sheet. It is very confusing, so here is a short example of code that illustrates the problem. ContentView:

import SwiftUI

extension String {
    var isValidNumber: Bool {

        let formatter = NumberFormatter()
        formatter.locale = Locale.current
        formatter.numberStyle = .decimal

        return formatter.number(from: self) != nil
    }
}

struct ContentView: View {

    @State var priceTotal: String = ""
    @FocusState private var inputIsFocused: Bool
    @State private var validateInputAlert = false
    @State private var validateInputAlertErrorMessage = ""
    @State private var isAddDiversExpensesViewSheetPresented = false

    var body: some View {
        NavigationView {
            Form {
                Section {
                    TextField("Kosten €", text: $priceTotal)
                        .onChange(of: priceTotal) { newValue in
                            if !newValue.isValidNumber {
                                priceTotal = ""
                                validateInputAlertErrorMessage = "Please input valid number, e.g. 50.11"
                                validateInputAlert = true
                            }
                        }
                        .keyboardType(.decimalPad)
                    Button(action: {
                        isAddDiversExpensesViewSheetPresented = true
                    }) {
                        ZStack {
                            Image(systemName: "eurosign.circle")
                                .resizable()
                                .foregroundColor(.secondary)
                                .frame(width: 40, height: 40)
                        }
                    }
                }
                .sheet(isPresented: $isAddDiversExpensesViewSheetPresented) {
                    AddView()
                }
                .focused($inputIsFocused)
            }
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("OK") {
                        inputIsFocused = false
                    }
                }
            }
            .alert(isPresented: $validateInputAlert) {
                Alert(
                    title: Text("Invalid Input.").foregroundColor(.red),
                    message: Text(validateInputAlertErrorMessage),
                    dismissButton: .default(Text("OK"))
                )
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

AddView

//
//  AddView.swift
//  TestKeyboard
//
//  Created by Ralf Boernemeier on 16.09.23.
//

import SwiftUI

struct AddView: View {

    @State var priceTotal: String = ""
    @FocusState private var inputIsFocused: Bool
    @State private var validateInputAlert = false
    @State private var validateInputAlertErrorMessage = ""

    var body: some View {
        NavigationView {
            Form {
                Section {
                    TextField("Kosten €", text: $priceTotal)
                        .onChange(of: priceTotal) { newValue in
                            if !newValue.isValidNumber {
                                priceTotal = ""
                                validateInputAlertErrorMessage = "Please input valid number, e.g. 50.11"
                                validateInputAlert = true
                            }
                        }
                        .keyboardType(.decimalPad)
                }
                .focused($inputIsFocused)

            }
            .alert(isPresented: $validateInputAlert) {
                Alert(
                    title: Text("Invalid Input.").foregroundColor(.red),
                    message: Text(validateInputAlertErrorMessage),
                    dismissButton: .default(Text("OK"))

                )
            }
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("OK") {
                        inputIsFocused = false
                    }
                }
            }
        }
    }
}

struct AddView_Previews: PreviewProvider {
    static var previews: some View {
        AddView()
    }
}

In the main screen, even after an invalid number "50,,,10" has been entered, the input works perfectly, i.e. the OK is still effective after the alert has been confirmed. If I open a sheet via the € button, which has the same code as the main screen, then the button is disabled after an invalid number has been entered and the alert has been confirmed.

It would be really great if someone has an idea what I am doing wrong.

2      

Hi,

I managed to get it to work putting the sheet on the NavigationView, see if it works for you.

NavigationView {
  ...
}
.sheet(isPresented: $isAddDiversExpensesViewSheetPresented) {
    AddView()
}

3      

Thanks a lot @Hectorcrdna!

That was exactly the solution, so simple, but you have to come up with it :-)

2      

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.