2

I would like to have a modal sheet appear with several options for the user to choose from. (The share sheet is a perfect example.) When the user makes a selection, the option sheet disappears and a second sheet appears with the selected option. In the share sheet example, if the user selects print, the share sheet slides down and the print sheet pops up.

I can get the option sheet to appear easily enough. But I haven't figured out how to get the second sheet to appear. I tried attaching the sheet to an empty view and then used UserDefaults to set the bool that activates the second sheet. Nothing.

First Sheet

Button(action: {
   UserDefaults.standard.set(true, forKey: showSelectedOption)
   showOptionForm = true
}) {
   Image(systemName: "square.and.arrow.up")
}
.sheet(isPresented: $showOptionForm) {
   OptionView().environment(\.managedObjectContext, self.moc)
})

SecondSheet

EmptyView()
   .sheet(isPresented: $showSelectedOption) {
      SelectedOptionView().environment(\.managedObjectContext, self.moc)
}

I tried setting the bool shown below in .onAppear, but it does not get called when a modal sheet is dismissed. Is there a way to tell when a view is no longer being covered by a sheet? In UIKit it would have been presentationControllerDidDismiss(_:). Of course, this is assuming that my idea to attach the second sheet to an empty view is even workable.

let showSelectedOption = UserDefaults.standard.bool(forKey: "showSelectedOption")

1 Answer 1

4

Here is demo of possible approach - you activate second sheet in onDismiss of first one. Tested with Xcode 12 / iOS 14.

struct DemoTwoSheets: View {
    @State private var firstSheet = false
    @State private var secondSheet = false
    var body: some View {
        VStack {
            Button("Tap") { self.firstSheet = true }
                .sheet(isPresented: $firstSheet, onDismiss: {
                    self.secondSheet = true
                }) {
                    Text("First sheet")
                }
            EmptyView()
                .sheet(isPresented: $secondSheet) {
                    Text("Second sheet")
                }
        }
    }
}

Update:

Here is an alternate which works for SwiftUI 1.0 as well. Tested with Xcode 11.4 / iOS 13.4 and Xcode 12b5 / iOS 14.

struct DemoTwoSheets: View {
    @State private var firstSheet = false
    @State private var secondSheet = false
    var body: some View {
        VStack {
            Button("Tap") { self.firstSheet = true }
                .sheet(isPresented: $firstSheet, onDismiss: {
                    self.secondSheet = true
                }) {
                    Text("First sheet")
                }
                .background(Color.clear
                    .sheet(isPresented: $secondSheet) {
                        Text("Second sheet")
                    })
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Unfortunately, this doesn't work on Xcode 11.6 / iOS 13.6. I marked it correct since it will work when the next version of iOS is released. Maybe I can figure out an alternative using an ObservableObject...
See update with variant that works on iOS 13 as well.
One follow up question - when I use views with dismiss buttons, the second sheet can't be dismissed unless you swipe down. I tried using a presentationMode variable as well as a binding variable without success. I know this is a workaround for iOS13 but do you think there's a workaround way to dismiss the second sheet as well? Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.