Categories
iOS Swift SwiftUI

Presenting multiple sheets in SwiftUI

SwiftUI has multiple view modifiers for presenting sheets. If we just want to present a modal view, then we can use one of these:

func sheet<Content>(
isPresented: Binding<Bool>,
onDismiss: (() -> Void)? = nil,
content: @escaping () -> Content
) -> some View where Content : View
func sheet<Item, Content>(
item: Binding<Item?>,
onDismiss: (() -> Void)? = nil,
content: @escaping (Item) -> Content
) -> some View where Item : Identifiable, Content : View
view raw Sheets.swift hosted with ❤ by GitHub

The first requires a boolean binding, whereas the second an identifiable item. When dealing with views which need to present different views in a sheet, then the latter can be easily expanded to support that. We can create an enum, conform it to Identifiable and then add an optional @State property which selects the view we should be presenting. The Identifiable protocol requires implementing an id property, which we can easily do by reusing rawValue property of an enum with raw types. If we put all of this together, then we can write something like this:

struct ContentView: View {
enum Sheet: String, Identifiable {
case addItem, settings
var id: String { rawValue }
}
@State private var sheet: Sheet?
var body: some View {
VStack {
Button("Add Item", action: { sheet = .addItem })
Button("Settings", action: { sheet = .settings })
}
.sheet(item: $sheet, content: makeSheet)
}
@ViewBuilder
func makeSheet(_ sheet: Sheet) -> some View {
switch sheet {
case .addItem:
AddItemView()
case .settings:
SettingsView()
}
}
}

In the example above, I also separated the sheet view creation by having a separate function with an argument of type ContentView.Sheet. Since the function returns views with different types, then it needs to be annotated with @ViewBuilder. All in all it is a pretty concise and gives a nice call site where we just assign a sheet identifier to the sheet property.

If this was helpful, please let me know on Mastodon@toomasvahter or Twitter @toomasvahter. Feel free to subscribe to RSS feed. Thank you for reading.

Advertisement