swiftswiftuiswiftui-sheet

Make sheet the exact size of the content inside


Let's say I have a custom view inside of a sheet, something like this

VStack {
   Text("Title")
   Text("Some very long text ...")
}
.padding()
.presentationDetents([.height(250)])

How can I get the exact height of the VStack and pass it to the presentationDetents modifier so that the height of the sheet is exactly the height of the content inside?


Solution

  • Using the general idea made by @jnpdx including some updates such as reading the size of the overlay instead of the background, here is what works for me:

    struct ContentView: View {
        @State private var showSheet = false
        @State private var sheetHeight: CGFloat = .zero
    
        var body: some View {
            Button("Open sheet") {
                showSheet = true
            }
            .sheet(isPresented: $showSheet) {
                VStack {
                    Text("Title")
                    Text("Some very long text ...")
                }
                .padding()
                .overlay {
                    GeometryReader { geometry in
                        Color.clear.preference(key: InnerHeightPreferenceKey.self, value: geometry.size.height)
                    }
                }
                .onPreferenceChange(InnerHeightPreferenceKey.self) { newHeight in
                    sheetHeight = newHeight
                }
                .presentationDetents([.height(sheetHeight)])
            }
        }
    }
    
    struct InnerHeightPreferenceKey: PreferenceKey {
        static let defaultValue: CGFloat = .zero
        static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
            value = nextValue()
        }
    }