Search code examples
swiftswiftuiios16

How to size content for presentation detents in SwiftUI


I can display a sheet with a custom height with detents in SwiftUI like this.

.sheet(isPresented: $showSheet) {
    MySheet()
        presentationDetents([.height(500), .large])
}

Is there a way that I can measure the exact height of my view MySheet and pass this to presentationDetents without having a fixed value? I ask because based on the user's accessibility settings the height of the view could change.


Solution

  • Approach:

    • Measure the size of the content being presented and set the value into a @State variable
    • Use GeometryReader in the background of the content being presented to measure the height of content.
    • GeometryReader is added to the background of the content being presented and not to the foreground because GeometryReader tends to expand to all the space given to it like color or shape.

    Note:

    • This is one crude way to do it, happy to hear any better approaches
    • For multiline text please add .fixedSize(horizontal: false, vertical: true) to the text

    Code

    struct ContentView: View {
        @State private var isSheetShown = false
        @State private var sheetContentHeight = CGFloat(0)
    
        var body: some View {
            Button("Show sheet") {
                isSheetShown = true
            }
            .sheet(isPresented: $isSheetShown) {
                VStack {
                    Text("hello line 1")
                    Text("hello line 2")
                    Text("hello line 3")
                }
                .background {
                    //This is done in the background otherwise GeometryReader tends to expand to all the space given to it like color or shape.
                    GeometryReader { proxy in
                        Color.clear
                            .task {
                                print("size = \(proxy.size.height)")
                                sheetContentHeight = proxy.size.height
                            }
                    }
                }
                .presentationDetents([.height(sheetContentHeight)])
            }
        }
    }