The method of calling an alert in swiftUI is supposed to be simpler than ever, a simple example of this would be
struct ContentView: View {
@State private var showingAlert = false
var body: some View {
Button(action: {
self.showingAlert = true
}) {
Text("Show Alert")
}
.alert(isPresented: $showingAlert) {
Alert(title: Text("Important message"), message: Text("Wear sunscreen"), dismissButton: .default(Text("Got it!")))
}
}
}
However, even though I am calling an alert and can verify the method is being called, my alert does not display.
In my code I have the following Struct
private struct resetButton: View {
@State var isResetting = false
var body: some View {
Button("Reset"){
self.isResetting = true
}.alert(isPresented: $isResetting) {
print("We get here")
return
Alert(title: Text("Are you sure?"), message: Text("This will erase your Access Key."), primaryButton: .destructive(Text("Reset")) {
clearToken()
clearAccessKey()
clearUsername()
}, secondaryButton: .cancel(Text("Cancel")))
}
}
}
Which is called in the main view simply by resetButton()
.
However, when I push this button, despite isResetting
equalling true, the alert does not display. I have verified that my .alert
method is being called as the console prints
we get here
the first time the button is pushed.
However, the Alert is never displayed.
An alert is displayed correctly elsewhere in this same view with
.alert(isPresented: $failedLogin) {
self.password = ""
return
Alert(title: Text("Invalid Login"), message: Text("Please verify your credentials and try again"), dismissButton: .default(Text("Ok")))
}
When a @State
variable named failedLogin
is set true, however, the aforementioned alert is never presented.
My first impression is that this may be a bug in Swift, if it is I'll report it to apple. However, maybe something I'm doing isn't working because of an error on my part.
Edit:
As clarified in the answer below, the problem seems to be relating to the fact that my resetButton()
was trying to throw up an alert in a view that already contains an alert. Apparently you can't have multiple alerts in one view.
Build and present custom alerts to your users Presenting system alerts on SwiftUI is super simple. Just call an instance method alert and pass a few parameters, and you are done.
We can show alerts to the user in SwiftUI with an alert() modifier. Present without data. Present with data.
You can show alerts dynamically by using .alert(item:) instead .alert(isPresented:):
struct AlertItem: Identifiable {
var id = UUID()
var title: Text
var message: Text?
var dismissButton: Alert.Button?
}
struct ContentView: View {
@State private var alertItem: AlertItem?
var body: some View {
VStack {
Button("First Alert") {
self.alertItem = AlertItem(title: Text("First Alert"), message: Text("Message"))
}
Button("Second Alert") {
self.alertItem = AlertItem(title: Text("Second Alert"), message: nil, dismissButton: .cancel(Text("Some Cancel")))
}
Button("Third Alert") {
self.alertItem = AlertItem(title: Text("Third Alert"))
}
}
.alert(item: $alertItem) { alertItem in
Alert(title: alertItem.title, message: alertItem.message, dismissButton: alertItem.dismissButton)
}
}
}
So i'm still not 100% sure why this was unable to post an alert this way? But I was able to fix this issue simply by placing the alert in the main view.
I changed the @State
variable isResetting
to a binding bool and paced a new state variable in the main class. I then just copied over the .alert
and this seems to solve the issue.
The struct now looks like this
private struct resetButton: View {
@Binding var isResetting: Bool
var body: some View {
Button("Reset"){
self.isResetting = true
}
}
}
and the alert is the same but is now in the class calling resetButton()
.
Edit:
So it appears that SwiftUI won't let you call multiple alerts from the same view, however, if you want multiple alerts in the same view then there is a way around this.
You can call an alert from anywhere inside of a view so the following solution works.
private struct exampleAlert: View {
@State var alert1 = false
@State var alert2 = false
var body: some View {
Vstack{
Button("alert 1"){
self.alert1 = true
}.alert(isPresented: $alert1) {
Alert(title: Text("Important message"), message: Text("This alert can show"), dismissButton: .default(Text("Got it!")))
}
Button("alert 2"){
self.alert2 = true
}.alert(isPresented: $alert2) {
Alert(title: Text("Important message"), message: Text("This alert can also show"), dismissButton: .default(Text("Got it!")))
}
}
}
}
The catch is here that if either of these alerts were to be placed on the Vstack, one will not function. If they are placed on separate views though then both can be called as expected.
Perhaps this is something that will be rectified in a future update? In the meantime though, here is a solution for working around this problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With