TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

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      

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

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.