SwiftUI cannot dismiss the second sheet presented

I have a SwiftUI view with a button "Show sheet", when that button is pressed I would like to present the first view on the sheet. That view has a button to dismiss itself. If the Show sheet button is pressed again, now I would like to present the second view on the sheet, and it also has dismiss button. Here is the code:

struct FirstSheetView: View {
    @Binding var isPresented: Bool

    var body: some View {
       Button("Dismiss") {
                self.isPresented = false
            }
    }
}

struct SecondSheetView: View {
    @Binding var isPresented: Bool

    var body: some View {
       Button("Dismiss") {
                self.isPresented = false
            }
    }
}

enum ActiveSheet {
   case first, second
}

struct ContentView: View {
    @State private var isShowingPhotoSheet = false
    @State private var activeSheet: ActiveSheet = .first

    var body: some View {
            VStack {
                Button(action: {
                    self.isShowingPhotoSheet.toggle()
                }) {
                    Text("Show sheet")
                }
            }
            .sheet(
                isPresented: $isShowingPhotoSheet,
                onDismiss: loadSecondView,
                content: {
                    if self.activeSheet == .first {
                        FirstSheetView(isPresented: self.$isShowingPhotoSheet)
                    } else {
                        SecondSheetView(isPresented: self.$isShowingPhotoSheet)
                    }
                }
            )
    }

    private func loadSecondView() {
            activeSheet = .second
            self.isShowingPhotoSheet.toggle()

    }
}

The sheets are shown just fine, I am able to dismiss the first sheet, but not the second one (only with swiping it down), but it doesn't seem to do anything by pressing the "Dismiss" button. What could be the problem?

Upvotes: 2

Views: 676

Answers (1)

Asperi
Asperi

Reputation: 257749

The problem is that onDismiss is too early to set up second sheet, first one is still on screen and bound to state.

Here is a solution. Tested with Xcode 11.4 / iOS 13.4

private func loadSecondView() {
    if activeSheet == .second {
        activeSheet = .first
    } else {
        activeSheet = .second

        // give time to close first sheet
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            self.isShowingPhotoSheet = true
        }
    }
}

Upvotes: 2

Related Questions