How to Have Two Alerts on One View in Swiftui

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

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"))
}
}
}
}

How to show two alerts in swift ui one followed by the other

You cannot make two .alert calls directly behind each other without overwriting one of them. The key is to get all the logic inside a single .alert call.

import SwiftUI

enum ActiveAlert {
case first, second, third
}

struct ContentView: View {
@State private var showingAlert = false
@State private var activeAlert: ActiveAlert = .first

var body: some View {
Button(action: {
self.showAlert(.first)
}, label: {
Text("button")
.alert(isPresented: $showingAlert) {
switch activeAlert {
case .first:
return Alert(title: Text("First Alert"), dismissButton: .default(Text("Next"), action: {
self.showAlert(.second)
}))
case .second:
return Alert(title: Text("Second Alert"), dismissButton: .default(Text("Next"), action: {
self.showAlert(.third)
}))
case .third:
return Alert(title: Text("Third Alert"), dismissButton: .default(Text("Ok"), action: {
//...
}))
}
}
})
}

func showAlert(_ active: ActiveAlert) -> Void {
DispatchQueue.global().async {
self.activeAlert = active
self.showingAlert = true
}
}
}

Multiple Alerts in one view can not be called SwiftUI

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.

Multiple Alerts in one view can only the last alert works always in swiftui

The thing to remember is that view modifiers don't really just modify a view, they return a whole new view. So the first alert modifier returns a new view that handles alerts in the first way. The second alert modifier returns a new view that modifies alerts the second way (overwriting the first method) and that's the only one that ultimately is in effect. The outermost modifier is what matters.

There are couple things you can try, first try attaching the different alert modifiers to two different view, not the same one.

Second you can try the alternate form of alert that takes a Binding of an optional Identifiable and passes that on to the closure. When value is nil, nothing happens. When the state of changes to something other than nil, the alert should appear.

Here's an example using the alert(item:) form as opposed to the Bool based alert(isPresented:).

enum Selection: Int, Identifiable {
case a, b, c
var id: Int { rawValue }
}


struct MultiAlertView: View {

@State private var selection: Selection? = nil

var body: some View {

HStack {
Button(action: {
self.selection = .a
}) { Text("a") }

Button(action: {
self.selection = .b
}) { Text("b") }

}.alert(item: $selection) { (s: Selection) -> Alert in
Alert(title: Text("selection: \(s.rawValue)"))
}
}
}

How to consecutively present two alert views using SwiftUI

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")))
}
}
}
}

config 2 alerts messages in button swiftUI

For multiple alerts in a single view, you can use an enum.

First, you need to create an enum like this and define all the alert message

enum AlertType: Identifiable {
var id: UUID {
return UUID()
}

case success
case error

var title: String {
switch self {
case .success:
return "Success !"
case .error:
return "Error !"
}
}

var message: String {
switch self {
case .success:
return "Insert with success !"
case .error:
return "This category already exist !!"
}
}
}

now create one state var in the view.

struct NewCategoryView: View {
@State private var alertType: AlertType?

// Other code
}

and add the alert at the end

//end Vstak
.navigationTitle("New Category")
.onAppear(perform: { updateCategoryList()} )
.alert(item: self.$alertType, content: { (type) -> Alert in
Alert(title: Text(type.title), message: Text(type.message),
dismissButton: .default(Text("OK")))
})

now show the alert by assigning the value. Like this

if condition_true {
alertType = AlertType.success //<-- Here
} else {
alertType = AlertType.error //<-- Here
}

SwiftUI Multiple alerts for same button

You can apply .alert only once to a View. Create a State which only handles the current State of the Alert and then two variables which decide if false or true was pressed. (might store that in one variable only aswell)

struct ContentView6: View {

@State var showAlert : Bool = false

@State var showTrueAlert = false
@State var showFalseAlert = false

var body: some View {
Button(action: {
let isTrue = Bool.random()
if isTrue
{
self.showTrueAlert = true
self.showAlert = true
print("True Alert")
} else {
self.showFalseAlert = true
self.showAlert = true
print("False Alert")
}
}) {

Text("Random Alert")
.font(.largeTitle)
}
.alert(isPresented: Binding<Bool>(
get: {
self.showAlert
},
set: {
self.showAlert = $0
self.showTrueAlert = false
self.showFalseAlert = false
})) {
if (showTrueAlert)
{
return Alert(title: Text("True"))
}
else
{
return Alert(title: Text("False"))
}
}
}
}

Is it possible to create an alert with more than 2 buttons in SwiftUI?

This is now possible on iOS 15/macOS 12 with a new version of the alert modifier: alert(_:isPresented:presenting:actions:).

It works a bit differently because the Alert struct isn't used anymore; you use regular SwiftUI Buttons instead. Add a ButtonRole to indicate which buttons perform the "cancel" action or "destructive" actions. Add the .keyboardShortcut(.defaultAction) modifier to a button to indicate it performs the principal action.

For example:

MyView()
.alert("Test", isPresented: $presentingAlert) {
Button("one", action: {})
Button("two", action: {}).keyboardShortcut(.defaultAction)
Button("three", role: .destructive, action: {})
Button("four", role: .cancel, action: {})
}

Creates the following alert:

Alert



Related Topics



Leave a reply



Submit