Reading time: 1 min
This recipe shows how to present multiple sheets or full screen covers on a single view in SwiftUI. It saves you from having to have multiple modifiers with isPresented
, each holding their own view. Also, it automatically takes care of switching between different sheets / covers with just a single binding.
The end result looks like this:
The key here is to use the item
variant instead of isPresented
. Instead of binding to a boolean, you bind to an Identifiable
optional. If the value is nil
, the sheet / cover isn't presented. When the value changes, the sheet / cover goes up, and you can decide on its content based on the value of the binding.
The best way of going about it is to declare the sheet / cover view variants in an enum. It's also dead easy to make it conform to Identifiable
, since enums without associated values can use themselves as ObjectIdentifier
:
enum Screen: Identifiable, CaseIterable {
case red, blue, green
var id: Self {
self
}
var color: Color {
switch self {
case .red:
return .red
case .blue:
return .blue
case .green:
return .green
}
}
}
Then, use the enum in an optional Binding
to control when and what to show:
struct PopoverTest: View {
@State private var screen: Screen?
var body: some View {
Button("Random color") {
screen = Screen.allCases.randomElement() // show the popover
}
.fullScreenCover(item: $screen, onDismiss: nil) { currentScreen in
ZStack {
Rectangle()
.foregroundColor(currentScreen.color)
Button("Reset") {
self.screen = nil // hide the popover again
}
.foregroundColor(.white)
}
}
}
}
fullScreenCover
is only available from SwiftUI 2 (iOS 14, macOS 11), so can check out drop-in replacement that works on any version!