skip to Main Content

I have a simple view where you can show an alert and then click the "Yes" button to dismiss it. The issue I’m having is that when tapping "Yes", the print() statement fires only after the alert is fully dismissed, not immediately. I’m assuming this is caused by the default animation but not certain.

How can I make it fire the closure immediately upon tapping "Yes"?

import SwiftUI

struct ContentView: View {
    @State private var show = false
    
    var body: some View {
        VStack {
            Button("Show Alert") {
                show = true
            }
        }
        .alert("Cancel exposure?", isPresented: $show) {
            Button("Yes", role: .destructive) {
                print("Dismissing") // Should show immediately when tapping "Yes"
            }
            
            Button("No", role: .cancel) { }
        }
    }
}

#Preview {
    ContentView()
}

2

Answers


  1. You can try something like this with – onChanage..

    struct ContentView: View {
            @State private var show = false
            @State private var alertButtonOkPressed = false
            
            var body: some View {
                VStack {
                    Button("Show Alert") {
                        show = true
                    }
                }
                .onChange(of: alertButtonOkPressed) {
                    print("Dismissing")
                }
                .alert("Cancel exposure?", isPresented: $show) {
                    Button("Yes", role: .destructive) {
                        alertButtonOkPressed = true
                    }
                    Button("No", role: .cancel) { }
                }
            }
        }
    
    Login or Signup to reply.
  2. This behavior is present in UIKit as well, you can see it if you change the alert to fullScreenCover

    .fullScreenCover(isPresented: $show) {
        AlertWrapper()
            .presentationBackground {
                Color.clear
            }
    }
    

    And use this wrapper

    struct AlertWrapper: UIViewControllerRepresentable {
        func makeUIViewController(context: Context) -> some UIViewController {
            let alert = UIAlertController(title: "My Alert", message: "This is an alert.", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Default action"), style: .default, handler: { _ in
                NSLog("The "OK" alert occured.")
            }))
            return alert
        }
        func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
            
        }
    }
    

    An alternative is to use a fullScreenCover with Custom UI.

    struct AlertTestView: View {
        @State private var show = false
        var body: some View {
            VStack {
                Button("Show Alert") {
                    show = true
                }
            }.fullScreenCover(isPresented: $show) {
                RoundedRectangle(cornerRadius: 8)
                    .fill(Color(uiColor: .systemBackground))
                    .overlay {
                        //Make this to look like an alert
                        VStack {
                            Text("Cancel exposure?")
                            HStack{
                                Button("Yes", role: .destructive) {
                                    print("Dismissing") // Should show immediately when tapping "Yes"
                                    
                                    show.toggle()
                                }
                                
                                Button("No", role: .cancel) { }
                            }
                        }
                        .padding()
                    }
                    .aspectRatio(1.5, contentMode: .fit)
                    .frame(height: 200)
                    .padding(50)
                    .presentationBackground {
                        Color.gray.opacity(0.2)
                    }
            }
        }
    }
    

    Just as an added note, you can easily see this behavior if you use "Slow Animations" in the simulator.

    enter image description here

    This should also be submitted as a bug since both the SwiftUI and UIKit versions are behaving against documentation.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search