3

I want to immediately present the second alert view after click the dismiss button of the first alert view.

Button(action: {
     self.alertIsVisible = true
}) {
     Text("Hit Me!")
}
.alert(isPresented: $alertIsVisible) { () -> Alert in
    return Alert(title: Text("\(title)"), message: Text("\n"), dismissButton:.default(Text("Next Round"), action: {
        if self.score == 100 {
            self.bonusAlertIsVisible = true
    }
    .alert(isPresented: $bonusAlertIsVisible) {
        Alert(title: Text("Bonus"), message: Text("You've earned 100 points bonus!!"), dismissButton: .default(Text("Close")))}
})
)

However, it gives me an error of 'Alert.Button' is not convertible to 'Alert.Button?' If I put this segment out of the scope of dismissButton, it will override the previous .alert. So how can i do it, I just want to pop up the second alert after clicking the dismiss button of the first alert. Thanks.

Dawei Xu
  • 314
  • 1
  • 11
  • Does this answer your question? [How can I have two alerts on one view in SwiftUI?](https://stackoverflow.com/questions/58069516/how-can-i-have-two-alerts-on-one-view-in-swiftui) – Rohit Makwana Nov 13 '19 at 10:06
  • Nope, it's different, i also tried that one, but you need to click the "Hit me" button twice to pop up the second alert view, I want to click the dismiss button of the first alert – Dawei Xu Nov 13 '19 at 10:36

2 Answers2

9

It appears (tested with Xcode 11.2):

  1. While not documented, but it is not allowed to add more than one .alert modifier in one view builder sequence - works only latest
  2. It is not allowed to add .alert modifier to EmptyView, it does not work at all

I've found alternate solution to proposed by @Rohit. In some situations, many alerts, this might result in simpler code.

struct TestTwoAlerts: View {
    @State var alertIsVisible = false
    @State var bonusAlertIsVisible = false

    var score = 100
    var title = "First alert"

    var body: some View {
        VStack {
            Button(action: {
                 self.alertIsVisible = true
            }) {
                 Text("Hit Me!")
            }
            .alert(isPresented: $alertIsVisible) {
                Alert(title: Text("\(title)"), message: Text("\n"), dismissButton:.default(Text("Next Round"), action: {
                    if self.score == 100 {
                        DispatchQueue.main.async { // !! This part important !!
                            self.bonusAlertIsVisible = true
                        }
                    }
                }))
            }
            Text("")
            .alert(isPresented: $bonusAlertIsVisible) {
                    Alert(title: Text("Bonus"), message: Text("You've earned 100 points bonus!!"), dismissButton: .default(Text("Close")))
            }
        }
    }
}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Cheers man! Can you tell me what will happen when we add this part of code: DispatchQueue.main.async { self.bonusAlertIsVisible = true }? – Dawei Xu Nov 14 '19 at 01:47
  • 1
    This state will be changed in the next event on the main loop, so will not conflict with the first alert, which is still opened. If change this state synchronously it will not work, because there can't be two opened alerts here. – Asperi Nov 14 '19 at 04:25
2

Please try below code.

Consecutively present two alert views using SwiftUI

struct ContentView: View {

    @State var showAlert: Bool = false
    @State var alertIsVisible: Bool = false
    @State var bonusAlertIsVisible: Bool = false

    var body: some View {

        NavigationView {

            Button(action: {
                self.displayAlert()
            }) {
                Text("Hit Me!")
            }
            .alert(isPresented: $showAlert) { () -> Alert in
                if alertIsVisible {
                    return Alert(title: Text("First alert"), message: Text("\n"), dismissButton:.default(Text("Next Round"), action: {
                        DispatchQueue.main.async {
                            self.displayAlert()
                        }
                     })
                   )
                }
                else {
                    return Alert(title: Text("Bonus"), message: Text("You've earned 100 points bonus!!"), dismissButton:.default(Text("Close"), action: {
                                self.showAlert = false
                                self.bonusAlertIsVisible = false
                                self.alertIsVisible = false
                        })
                    )
                }
            }
            .navigationBarTitle(Text("Alert"))
        }
    }

    func displayAlert() {

       self.showAlert = true
       if self.alertIsVisible == false {
            self.alertIsVisible = true
            self.bonusAlertIsVisible = false
       }
       else {
            self.alertIsVisible = false
            self.bonusAlertIsVisible = true
       }
    }
}
Rohit Makwana
  • 4,337
  • 1
  • 21
  • 29
  • Genius man! So it's like if we asycnly add $showAlert=false into main dispatchqueue, it will present the .alert twice without need to click the button? – Dawei Xu Nov 14 '19 at 01:39