Clean Up Your Sheet API
If you are like most developers, you probably have more parameters than are required to get a working sheet in SwiftUI. Please pardon the potty humor and let’s work together and get that API cleaned up.
Before we get started, please take a couple of seconds to follow me and 👏 clap for the article so that we can help more people learn about this useful content.
Most Sheet APIs
Many developers (including myself) have writing code that is similar to the following. In this example, we are passing a binding to the sheet. Once in the sheet view, we are using that binding to close the sheet. There isn’t really much wrong with this implementation except that our sheet view has an unnecessarily long API, and it would probably be worse if this was more than a quick tutorial. So what do we do to fix it?
// ContentView.swift
import SwiftUI
struct ContentView: View {
@State var isShowingMyCustomSheet = false
var body: some View {
VStack {
Button("Toggle the Sheet") {
isShowingMyCustomSheet.toggle()
}
}
.padding()
.sheet(isPresented: $isShowingMyCustomSheet) {
// our long sheet API
MySheetView(isShowingMyCustomSheet: $isShowingMyCustomSheet)
}
}
}
struct MySheetView: View {
@Binding var isShowingMyCustomSheet: Bool
var body: some View {
VStack {
HStack {
Spacer()
Button {
isShowingMyCustomSheet.toggle()
} label: {
Image(systemName: "xmark")
}
}.padding()
Spacer()
// If you want this image for your project, you can save the title
// image from this article to your project file
Image(.poopEmojiCharacter)
.resizable()
.scaledToFit()
Spacer()
}
}
}
#Preview {
ContentView()
}
Environment variables for the win
In this cleaned up version of the sheet view, we swapped the Binding to the parents state variable with an environment variable. This environment variable is meant to dismiss any view. The dismiss environment variable works with sheets and NavigationStacks, and is a great tool to have in your developer toolbelt.
// ContentView.swift
import SwiftUI
struct ContentView: View {
@State var isShowingMyCustomSheet = false
var body: some View {
VStack {
Button("Toggle the Sheet") {
isShowingMyCustomSheet.toggle()
}
}
.padding()
.sheet(isPresented: $isShowingMyCustomSheet) {
// Our short sheet API
MySheetView()
}
}
}
struct MySheetView: View {
@Environment(\.dismiss) var dismiss
var body: some View {
VStack {
HStack {
Spacer()
Button {
dismiss()
} label: {
Image(systemName: "xmark")
}
}.padding()
Spacer()
// If you want this image for your project, you can save the title
// image from this article to your project file
Image(.poopEmojiCharacter)
.resizable()
.scaledToFit()
Spacer()
}
}
}
#Preview {
ContentView()
}
If you got value from this article, please consider following me, 👏 clapping for this article, or sharing it to help others more easily find it.
If you have any questions on the topic or know of another way to accomplish the same task, feel free to respond to the post or share it with a friend and get their opinion on it (just be nice about it). If you want to learn more about native mobile development, you can check out the other articles I have written here: https://medium.com/@jpmtech. If you want to see apps that have been built with native mobile development, you can check out my apps here: https://jpmtech.io/apps. Thank you for taking the time to check out my work!