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.