Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I have two alerts on one view in SwiftUI?

Tags:

swift

swiftui

I want to have two unique alerts attached to the same Button view. When I use the code below, only the alert on the bottom works.

I'm using the official release of Xcode 11 on macOS Catalina.

@State private var showFirstAlert = false @State private var showSecondAlert = false  Button(action: {     if Bool.random() {         showFirstAlert = true     } else {         showSecondAlert = true     } }) {     Text("Show random alert") } .alert(isPresented: $showFirstAlert) {     // This alert never shows     Alert(title: Text("First Alert"), message: Text("This is the first alert")) } .alert(isPresented: $showSecondAlert) {     // This alert does show     Alert(title: Text("Second Alert"), message: Text("This is the second alert")) } 

I expect first alert to show when I set showFirstAlert to true and I expect the second alert to show when I set showSecondAlert to true. Only the second alert shows when its state is true but the first one does nothing.

like image 560
Luke Chambers Avatar asked Sep 23 '19 20:09

Luke Chambers


People also ask

How do I show custom alerts in SwiftUI?

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.

How do I show messages in SwiftUI?

We can show alerts to the user in SwiftUI with an alert() modifier. Present without data. Present with data.


2 Answers

The second call to .alert(isPresented) is overriding the first. What you really want is one Binding<Bool> to denote whether the alert is presented, and some setting for which alert should be returned from the closure following .alert(isPresented). You could use a Bool for this, but I went ahead and did it with an enum, as that scales to more than two alerts.

enum ActiveAlert {     case first, second }  struct ToggleView: View {     @State private var showAlert = false     @State private var activeAlert: ActiveAlert = .first      var body: some View {          Button(action: {             if Bool.random() {                 self.activeAlert = .first             } else {                 self.activeAlert = .second             }             self.showAlert = true         }) {             Text("Show random alert")         }         .alert(isPresented: $showAlert) {             switch activeAlert {             case .first:                 return Alert(title: Text("First Alert"), message: Text("This is the first alert"))             case .second:                 return Alert(title: Text("Second Alert"), message: Text("This is the second alert"))             }         }     } } 
like image 109
John M. Avatar answered Oct 23 '22 19:10

John M.


There's a variation on this solution which only uses one state variable rather than two. It uses the fact that there is another .alert() form which takes an Identifiable item rather than a Bool, so extra information can be passed in that:

struct AlertIdentifier: Identifiable {     enum Choice {         case first, second     }      var id: Choice }  struct ContentView: View {     @State private var alertIdentifier: AlertIdentifier?      var body: some View {         HStack {             Button("Show First Alert") {                 self.alertIdentifier = AlertIdentifier(id: .first)             }             Button("Show Second Alert") {                 self.alertIdentifier = AlertIdentifier(id: .second)             }         }         .alert(item: $alertIdentifier) { alert in             switch alert.id {             case .first:                 return Alert(title: Text("First Alert"),                              message: Text("This is the first alert"))             case .second:                 return Alert(title: Text("Second Alert"),                              message: Text("This is the second alert"))             }         }     } } 
like image 30
Ben Avatar answered Oct 23 '22 19:10

Ben