Created
May 3, 2025 15:25
-
-
Save mdb1/f41a7b677af6e8b00e47cfa35136bd22 to your computer and use it in GitHub Desktop.
Documentation for Sheets usage in SwiftUI + a modifier for the close button in the navigation bar
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
extension View { | |
/// For sheets, we will follow the SwiftUI built-in approach: | |
/// | |
/// If we only need to present one possible sheet, we can use a Boolean binding and use `.sheet(isPresented:)` | |
/// | |
/// `.sheet(isPresented:)` | |
/// =================================== | |
/// ```swift | |
/// struct SomeScreen: View { | |
/// @State private var isPresentingSheet: Bool = false | |
/// | |
/// var body: some View { | |
/// Button("Present Sheet") { | |
/// isPresentingSheet = true | |
/// } | |
/// .sheet(isPresented: $isPresentingSheet) { | |
/// Text("Presented sheet") | |
/// } | |
/// } | |
/// } | |
/// ``` | |
/// | |
/// In case there is a screen that can present multiple type of sheets, we can use enum-based presentation: | |
/// | |
/// `sheet(item:)` | |
/// =================================== | |
/// ```swift | |
/// struct SomeScreen: View { | |
/// enum Sheet: String, Identifiable { | |
/// case firstPresentedScreen, secondScreen, thirdScreen | |
/// var id: String { rawValue } | |
/// } | |
/// | |
/// @State private var presentedSheet: Sheet? | |
/// | |
/// var body: some View { | |
/// VStack { | |
/// Button("Present Sheet") { | |
/// presentedSheet = .firstPresentedScreen | |
/// } | |
/// Button("Present Second Sheet") { | |
/// presentedSheet = .secondScreen | |
/// } | |
/// Button("Present Third Sheet") { | |
/// presentedSheet = .thirdScreen | |
/// } | |
/// } | |
/// .sheet(item: $presentedSheet) { sheet in | |
/// switch sheet { | |
/// case .firstPresentedScreen: | |
/// Text("First presented screen") | |
/// case .secondScreen: | |
/// Text("Second screen") | |
/// case .thirdScreen: | |
/// Text("Third screen") | |
/// } | |
/// } | |
/// } | |
/// } | |
/// ``` | |
/// | |
/// Detents / DragIndicator / CloseButton | |
/// =================================== | |
/// If we need to display different detents, we can just use the `.detents` modifier: | |
/// ```swift | |
/// struct SomeScreen: View { | |
/// @State private var isPresentingSheet: Bool = false | |
/// | |
/// var body: some View { | |
/// Button("Present Sheet") { | |
/// isPresentingSheet = true | |
/// } | |
/// .sheet(isPresented: $isPresentingSheet) { | |
/// NavigationStack { | |
/// Text("Presented sheet") | |
/// .presentationDetents([.medium, .large]) // <---- HERE | |
/// .presentationDragIndicator(.visible) // Displays the drag indicator | |
/// .withNavigationCloseButton { isPresentingSheet = false } | |
/// } | |
/// } | |
/// } | |
/// } | |
/// ``` | |
func withNavigationCloseButton(onTap: @escaping () -> Void) -> some View { | |
modifier(CloseModalButtonModifier(onTap: onTap)) | |
} | |
} | |
/// A `ViewModifier` that adds a Close button to the navigation bar on the trailing position. | |
/// Used within screens that are presented modally. | |
struct CloseModalButtonModifier: ViewModifier { | |
var onTap: () -> Void | |
func body(content: Content) -> some View { | |
content | |
.toolbar { | |
ToolbarItem(placement: .topBarTrailing) { | |
// TODO: Replace with your custom Close Button for the Nav Bar | |
Button("Close".localized) { | |
onTap() | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment