squarehippo10
squarehippo10

Reputation: 1945

SwiftUI - present sheet programatically

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")

Upvotes: 2

Views: 1816

Answers (1)

Asperi
Asperi

Reputation: 257653

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")
                    })
        }
    }
}

Upvotes: 4

Related Questions