2

I am creating a custom alert reusable modifier which will have different number of buttons depending upon the style I need. Anyways in my sample code below, I have removed as much extra code as I can to keep it small and simple.

With the code below, I am able to show the alert, but clicking on "Click Me" button does not dismiss the alert. I feel something is wrong with the way I am setting "isPresented" binding variable, but not able to figure out what. Am new to SwiftUI.

Custom Alert Modifier:

struct CustomAlertView: ViewModifier {
    var isPresented: Binding<Bool>

    init(isPresented: Binding<Bool>) {
        self.isPresented = isPresented
    }

    func body(content: Content) -> some View {
        content.overlay(alertContent())
    }

    @ViewBuilder
    private func alertContent() -> some View {
        GeometryReader { geometry in
            if self.isPresented {
                // Do something

                // Setting isPresented to false is not doing anything when button is clicked.
                Button(action: { self.isPresented.wrappedValue = false }) { 
                    Text("Click Me")
                }
            }
        }
    }
}

func customAlert(isPresented: Binding<Bool>) -> some View {
    return modifier(CustomAlertView(isPresented: isPresented))
}

View and view model code:

struct MyView: View {
    @ObservedObject var viewModel: CustomViewModel = CustomViewModel()
    
    var body: some View {
        VStack {
            switch viewModel.state {
            case .idle:
                Color.clear.onAppear(perform: { viewModel.doSomething() })
            case .showNewView:
                // Navigate
            }
        }.onAppear() {
        viewModel.state = .idle
        }.customAlert(isPresented: .constant(viewModel.showAlert))
    }
}

@MainActor
class CustomViewModel: ObservableObject {
    enum State {
        case idle
        case showNewView
    }
    
    @Published var state = State.idle
    @Published var showAlert = false
    
    func doSomething() {
        if failure {
            self.showAlert = true
        } else {
            self.state = .showNewView
        }
    }
}

What am I doing wrong or why am I not able to dismiss the alert?

Thanks for looking!

tech_human
  • 6,592
  • 16
  • 65
  • 107

1 Answers1

2

First of all, you want @Binding var isPresented: Bool inside the CustomAlertView, and you assign it in init as self._isPresented = isPresented:

struct CustomAlertView: ViewModifier {
    @Binding var isPresented: Bool // <-- like this

    init(isPresented: Binding<Bool>) {
        self._isPresented = isPresented // <-- and like this
    }
//...

And second, you definitely don't want to set isPresented to a constant in .customAlert(isPresented: .constant(viewModel.showAlert)). Instead, you need to pass the binding variable:

VStack {
// ...
}
.customAlert(isPresented: $viewModel.showAlert) // <-- bind it here
timbre timbre
  • 12,648
  • 10
  • 46
  • 77