I am trying to fit the size of a sheet to its content. There is another question on StackOverflow addressing this topic.
However the problem is that GeometryReader
does not seem to work properly when used inside a sheet, combined with the usage of multiline text.
This is a simple example demonstrating the issue.
struct DemoView: View {
@State
var isSheetShown = false
let longText = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua."
var content: some View {
Text(longText)
}
@State
private var sheetHeight: CGFloat = 0
var body: some View {
VStack(spacing: 20) {
Button("Show sheet") {
isSheetShown.toggle()
}
.sheet(isPresented: $isSheetShown) {
self.content
.overlay {
GeometryReader { geometry in
let _ = print("Sheet height \(geometry.size.height)")
Color.clear.preference(key: InnerHeightPreferenceKey.self, value: geometry.size.height)
}
}
.onPreferenceChange(InnerHeightPreferenceKey.self) { newHeight in
self.sheetHeight = newHeight
}
.presentationDetents(
[.height(self.sheetHeight)]
)
}
}
}
}
// MARK: - Preference Key
private struct InnerHeightPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = .zero
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
When it is run, you will see in the console, that the body is rendered twice. In the first pass, the correct sheet height is calculated but then it's re-rendered and it seems to be adjusted to a smaller height, which leads to the text being cut of after one line.
Console output:
Sheet height 86.33333333333333
Sheet height 20.333333333333332
NOTE: When adding .lineLimit(nil)
to Text(longText)
doesn't change the behavior.
Strangely however, I can then also drag the sheet up, which leads to the desired sheet height being used, and the following additional console output:
Sheet height 42.33333333333333
Sheet height 64.33333333333333
Sheet height 86.33333333333333