TechnologiesSwiftUIPresentation and Dialogs

CustomPresentationDetent protocol

iOSmacOStvOSwatchOSvisionOSiOS 16.0+✓ renders

The definition of a custom detent with a calculated height.

How it works

A CustomPresentationDetent is a type you define to express a resting height for a presented sheet that the built-in detents — .medium and .large — can't describe. SwiftUI's presentation system snaps a sheet to one of the detents you supply; conforming to this protocol lets you add your own stopping point computed from the space currently available. Reach for it when a sheet should rest at a fraction of the screen, at a fixed point size, or at a height derived from its content, rather than at one of the standard fractions.

  1. Conform a type to CustomPresentationDetent

    A custom detent is a type — usually an empty struct — that adopts the protocol. It carries no stored state; it exists purely to vend a height. In the example, ThirdHeight conforms to CustomPresentationDetent and serves as the named identity for that resting position.

  2. Implement the height(in:) requirement

    The protocol's single requirement is the static method height(in:), which SwiftUI calls to ask how tall the sheet should be. Returning a CGFloat fixes the height in points; returning nil tells SwiftUI to ignore this detent for the current context. Here height(in:) returns context.maxDetentValue / 3 to rest at a third of the available space.

  3. Read the layout from Context

    The in context: parameter is a CustomPresentationDetent.Context describing the environment in which the height is being resolved. Its maxDetentValue reports the largest height a detent may occupy — effectively the room a .large detent would take — so you can compute proportional heights against it, as the example does with context.maxDetentValue / 3.

  4. Register the detent with .custom(_:)

    A custom detent reaches a sheet by being wrapped in the PresentationDetent.custom(_:) case, which takes the conforming type itself. Passing ThirdHeight.self to .custom(ThirdHeight.self) turns your type into a PresentationDetent value that the presentation system understands.

  5. Offer it through presentationDetents(_:)

    The set of allowed resting positions is declared on the sheet's content with the presentationDetents(_:) modifier, which accepts an array of PresentationDetent values. In the example .presentationDetents([.custom(ThirdHeight.self)]) makes the one-third height the sole detent the sheet can settle on.

Try it — Change context.maxDetentValue / 3 in height(in:) to context.maxDetentValue * 0.8 and the sheet will rest much higher, showing that the returned CGFloat directly sets the detent's height.

Example & preview

Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.

CustomPresentationDetent.swift
struct CustomPresentationDetentDemo: View {
    struct ThirdHeight: CustomPresentationDetent {
        static func height(in context: Context) -> CGFloat? {
            context.maxDetentValue / 3
        }
    }

    @State private var showSheet = true

    var body: some View {
        Color.clear
            .sheet(isPresented: $showSheet) {
                VStack(spacing: 12) {
                    Text("Custom Detent")
                        .font(.headline)
                    Text("Resting at one third of the available height.")
                        .multilineTextAlignment(.center)
                }
                .padding()
                .presentationDetents([.custom(ThirdHeight.self)])
            }
            .padding()
    }
}
Live preview
Custom Detent Resting at one third of the available height.
Custom Detent Resting at one third of the available height.
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →