fullScreenCover in SwiftUI
Similar to Sheet in SwiftUI, there are two ways to present a full screen modal view in SwiftUI as well.
To learn more about Sheet, take a look at my “Sheet in SwiftUI” post.
1. Binding to a Boolean value
In this way, SwiftUI will present a modal view that covers as much of the screen as possible when a binding to a Boolean value that you provide is true
.
The official method definition is below:
1
2
3
4
5
6
nonisolated
func fullScreenCover<Content>(
isPresented: Binding<Bool>,
onDismiss: (() -> Void)? = nil,
@ViewBuilder content: @escaping () -> Content
) -> some View where Content : View
Let’s use an example to illustrate how to use it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
struct TimelineListView: View {
@EnvironmentObject var timelineStore: TimelineStore
@State private var showingSettings = false
var body: some View {
NavigationView {
List(timelineStore.timelines) { timeline in
TimelineRow(timeline: timeline)
}
.navigationBarTitle("Timelines")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: { showingSettings = true }) {
Image(systemName: "gear")
}
}
}
.fullScreenCover(isPresented: $showingSettings, onDismiss: didDismiss) {
SettingsView()
}
}
}
private func didDismiss() {
// Handle the dismissing action.
}
}
In the above example, SwiftUI will present SettingsView
when showingSettings
is true
.
2. Using data source item
Another way to present a full screen modal view is using the given item as a data source for the modal view’s content.
The method definition is as follows:
1
2
3
4
5
6
nonisolated
func fullScreenCover<Item, Content>(
item: Binding<Item?>,
onDismiss: (() -> Void)? = nil,
@ViewBuilder content: @escaping (Item) -> Content
) -> some View where Item : Identifiable, Content : View
A simple example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct TimelineDetailView: View {
let timeline: Timeline
@State private var showingEventToEdit: Event? = nil
var body: some View {
List(timeline.events) { event in
EventRow(event: event)
.contentShape(Rectangle())
.onTapGesture {
showingEventToEdit = event
}
}
.navigationTitle(timeline.title)
.fullScreenCover(isPresented: $showingEventToEdit) { event in
EventEditView(timeline: timeline, event: event)
}
}
}
SwiftUI will present a EventEditView
when showingEventToEdit
has value.
Multiple modal views
Sometimes, we may need to present multiple full screen modal views in the same view. How to achieve this in a concise way?
We can create an enum like ModalView
to combine all modal views together.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
struct TimelineDetailView: View {
enum ModalView: Identifier {
case createEvent
case editEvent(Event)
var id: String {
switch self {
case .createEvent: return "createEvent"
case .editEvent(let event): return "editEvent-\(event.id)"
}
}
}
let timeline: Timeline
@State private var showingModalView: ModalView? = nil
var body: some View {
List(timeline.events) { event in
EventRow(event: event)
.contentShape(Rectangle())
.onTapGesture {
showingModalView = .editEvent(event)
}
}
.navigationTitle(timeline.title)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
showingModalView = .createEvent
} label: {
Image(systemName: "plus")
}
}
}
.fullScreenCover(item: $showingModalView) { modalView in
switch modalView {
case .createEvent:
EventCreateView(timeline: timeline)
case .editEvent(let event):
EventEditView(timeline: timeline, event: event)
}
}
}
}
Using this way, we can simply combine all full screen modal views together without multiple state definitions and fullScreenCover modifiers.