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:
This is the 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?