27

In SwiftUI I discovered the Alert type. But I wonder how to show it with the presentation method.

Initializing an Alert is pretty easy. But how to use the binding?

struct ContentView : View {
    var body: some View {
        Button(action: {
            // Don't know how to use the `binding` below
            presentation(binding, alert: {
                Alert(title: Text("Hello"))
            })
        }, label: {
            Text("asdf")
        })
    }
}

The binding is of type Binding<Bool>

Lukas Würzburger
  • 6,543
  • 7
  • 41
  • 75

10 Answers10

32

.presentation() was actually deprecated in Beta 4. Here is a version that currently works with the .alert() Modifier.

struct ContentView: View {
    @State var showsAlert = false
    var body: some View {
        Button(action: {
            self.showsAlert.toggle()
        }) {
            Text("Show Alert")
        }
        .alert(isPresented: self.$showsAlert) {
            Alert(title: Text("Hello"))
        }
    }
}
thisIsTheFoxe
  • 1,584
  • 1
  • 9
  • 30
  • 2
    How can we use it in a Helper? As we have to call Alert many times. – Rob Oct 01 '19 at 06:34
  • I would like to know as well. I would love to have a helper: "showAlert" which expects a title and a text. And for example shows a generic alert if no parameters are provided. I tried to implement this as an extension for view struct but no chance to get it working :/. – Schnodderbalken Nov 12 '19 at 12:34
  • You can make a [simple extension like this](https://stackoverflow.com/a/64533167/5623035) @Schnodderbalken – Mojtaba Hosseini Oct 26 '20 at 07:50
15

You can use a @State variable as the binding. Alternatively you can use a @EnvironmentObject variable that uses a BindableObject.

I think you need to call presentation on the root View to get it to work, adding it to a Stack, Group, etc. doesn't seem to work.

This snippet seems to do the trick. Note that @State variable is set to false after the alert is dismissed.

struct ContentView: View {

    @State var showsAlert = false

    var body: some View {
        Button(action: {
            self.showsAlert = true
        }, label: {
            Text("asdf")
        }).presentation($showsAlert, alert: {
            Alert(title: Text("Hello"))
        })
    }
}
tsp
  • 1,938
  • 18
  • 15
14

Full Code of Alert with dismiss and okay action:

Code:

import SwiftUI

struct ContentView: View {
    @State private var isAlert = false

    var body: some View {
            Button(action: {
                self.isAlert = true
            }) {
                Text("Click Alert")
                .foregroundColor(Color.white)
            }
            .padding()
            .background(Color.blue)
            .alert(isPresented: $isAlert) { () -> Alert in
                Alert(title: Text("iOSDevCenters"), message: Text("This Tutorial for SwiftUI Alert."), primaryButton: .default(Text("Okay"), action: {
                    print("Okay Click")
                }), secondaryButton: .default(Text("Dismiss")))
        }

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Output:

Output

Kirit Modi
  • 23,155
  • 15
  • 89
  • 112
10

Here's the solution for presenting multiple alerts. Works on iOS13-iOS15:

struct YourView: View {
    enum AlertType: Identifiable {
        case first, second
        
        var id: Int {
            hashValue
        }
    }
    
    @State var alertType: AlertType?
    
    var body: some View {
        VStack {
            Button("Show alert #1") {
                alertType = .first
            }
            
            Button("Show alert #2") {
                alertType = .second
            }
        }
        .alert(item: $alertType) { type in
            switch type {
            case .first:
                return Alert(title: Text("First alert"))
            case .second:
                return Alert(title: Text("Second alert"))
            }
        }
    }
}
ramzesenok
  • 5,469
  • 4
  • 30
  • 41
6

In addition to @tsp's answer, to display an alert with two buttons and handle button tap action, you can do as below:

@State var showAlert = false

var body: some View {
  Button(action: {
    self.showAlert = true
  }) {
    Text("Show Alert")
  }
  .presentation($showAlert) {
      Alert(title: Text("Title"), message: Text("Message..."),
          primaryButton: .default (Text("OK")) {
            print("OK button tapped")
          },
          secondaryButton: .cancel()
      )
  }
}

Result:

enter image description here

M Reza
  • 18,350
  • 14
  • 66
  • 71
4

SwiftUI present Alert

Example with onTapGesture

struct MyRow: View {
    @State private var showingAlert = false
    
    var body: some View {
        HStack {
            Text("Hello")
            Text("World")
        }
        .onTapGesture {
            self.showingAlert = true
        }
        .alert(isPresented: $showingAlert, content: {
            Alert(title: Text("Title"), message: Text("Message"), dismissButton: .default(Text("OK")))
        })
    }
}
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
  • I have been unable to get alerts to work from draggesture in swiftui. Anu idea how to do it in this case? Thanks! .overlay(Rectangle() .gesture( DragGesture(minimumDistance: 50) .onEnded { gesture in if correct gesture... { .alert(isPresented: $showAlert, content: { Alert()... this alert does not compile – Tim Jun 05 '20 at 20:13
2

In addition to @thisIsTheFoxe 's answer, you can implement a simple extension:

Extension

public extension View {
    func alert(isPresented: Binding<Bool>,
               title: String,
               message: String? = nil,
               dismissButton: Alert.Button? = nil) -> some View {

        alert(isPresented: isPresented) {
            Alert(title: Text(title),
                  message: {
                    if let message = message { return Text(message) }
                    else { return nil } }(),
                  dismissButton: dismissButton)
        }
    }
}

Usage:

So you can now use it easily like:

struct ContentView: View {
    @State var showsAlert = false
    var body: some View {
        Button("Show Alert") {
            self.showsAlert.toggle()
        }
        .alert(isPresented: $showsAlert, title: "title", message: "Message") // <- Here
    }
}
Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
1
struct ContentView: View {

    @State var aAlert = false

    var body: some View {
        Text("Alert").tapAction {
            self.aAlert = true
        }.presentation($aAlert, alert:{ Alert(title: Text("Alert"))})
    }
}
Markicevic
  • 1,025
  • 9
  • 20
CrazyPro007
  • 1,006
  • 9
  • 15
  • 1
    Can you elaborate on your answer a little bit? For example, explanations about interesting parts of your code snippet, or links to the documentation? – Richard-Degenne Jun 10 '19 at 16:01
1

SwiftUI

First create basic alert :

Alert(title: Text("Alert title"), message: Text("Alert message"), dismissButton: .default(Text("Got it!")))

Then define a bindable condition that tells when the alert will be visible or not. Toggle that condition to show/hide the alert.

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!")))
        }
    }
}
Prashant Gaikwad
  • 3,493
  • 1
  • 24
  • 26
-1
public extension View {
    func alert(isPresented: Binding<Bool>,
               title: String,
               message: String? = nil,
               dismissButton: Alert.Button? = nil) -> some View {

        alert(isPresented: isPresented) {
            Alert(title: Text(title),
                  message: {
                    if let message = message { return Text(message) }
                    else { return nil } }(),
                  dismissButton: dismissButton)
        }
    }
}
Ranoiaetep
  • 5,872
  • 1
  • 14
  • 39