Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI: Make sheet show content header or complete content

I'd like to have a SwiftUI sheet that either shows the header or complete content. Requiring iOS 16 is ok.

I already get the correct two measured heights a presentationDetents

import Foundation
import SwiftUI

struct ContentView: View {
    @State private var showSheet = false
    @State private var headerSize: CGSize = .zero
    @State private var overallSize: CGSize = .zero
    
    var body: some View {
        Button("View sheet") {
            showSheet = true
        }
        .sheet(isPresented: $showSheet) {
            Group {
                VStack(alignment: .leading) {
                    Text("Header")
                        .background(
                            GeometryReader { geometryProxy in
                                Color.clear
                                    .preference(key: HeaderSizePreferenceKey.self, value: geometryProxy.size)
                            }
                        )
                    Text("")
                    Text("Some very long text ...")
                    Text("Some very long text ...")
                    Text("Some very long text ...")
                    Text("Some very long text ...")
                    Text("Some very long text ...")
                    Text("Some very long text ...")
                    Text("Some very long text ...")
                    Text("Some very long text ...")
                } // VStack
                .padding()
                .background(
                    //measure without spacer
                    GeometryReader { geometryProxy in
                        Color.clear
                            .preference(key: SizePreferenceKey.self, value: geometryProxy.size)
                    }
                )
                Spacer()
            } // Group
            .onPreferenceChange(SizePreferenceKey.self) { newSize in
                overallSize.height = newSize.height
            }
            .onPreferenceChange(HeaderSizePreferenceKey.self) { newSize in
                headerSize.height = newSize.height
            }
            .presentationDetents([
                .height(headerSize.height),
                .height(overallSize.height)
            ]
            )
            
        } // sheet content
    }
}

struct HeaderSizePreferenceKey: PreferenceKey {
    static var defaultValue: CGSize = .zero
    static func reduce(value: inout CGSize, nextValue: () -> CGSize) { value = nextValue() }
}

struct SizePreferenceKey: PreferenceKey {
    static var defaultValue: CGSize = .zero
    static func reduce(value: inout CGSize, nextValue: () -> CGSize) { value = nextValue() }
}

struct MySheet_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

This code is based on ideas from Make sheet the exact size of the content inside

It almost works. This is the complete content size:

Complete content size

This is the header content size:

Header content size

What can I do that the last case shows the top of the content ("Header") instead of the center of the content?

like image 642
Gerd Castan Avatar asked Oct 13 '25 00:10

Gerd Castan


1 Answers

I had the same issue. I solved this by using a ScrollView with no axes.

    ScrollView([]) {
        // Content here
    }
    .ignoreSafeArea()
like image 181
adri567 Avatar answered Oct 14 '25 17:10

adri567



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!