I have the following situation: I need to display a sheet with the items user can pick. Since the amount of this items can be big, I added the ScrollView to display the items. Here's the way I implemented the sheet:
struct PickerModalView: View {
let title: LocalizedStringKey
let items: [String]
let onDismiss: () -> Void
let onSubmit: (String) -> Void
init(
title: LocalizedStringKey,
items: [String],
onDismiss: @escaping () -> Void = {},
onSubmit: @escaping (String) -> Void
) {
self.title = title
self.items = items
self.onDismiss = onDismiss
self.onSubmit = onSubmit
}
@Environment(\.dismiss) var dismiss
var body: some View {
VStack {
HStack {
Text(title)
.title2()
.foregroundColor(MXColor.textPrimary)
Spacer()
Button {
onDismiss()
dismiss()
} label: {
Image(MXImage.ic_modal_close)
}
}.padding(EdgeInsets(top: 12, leading: 16, bottom: 12, trailing: 16))
ScrollView {
VStack {
ForEach(items, id: \.self) { item in
PickerItemView(text: item) { clickedItem in
onSubmit(clickedItem)
dismiss()
}
}
}
}.background(.red)
}.background(MXColor.surfacePrimary)
}
}
struct PickerItemView: View {
let text: String
let onClick: (String) -> Void
var body: some View {
Button {
onClick(text)
} label: {
HStack {
Text(text).foregroundColor(MXColor.textPrimary)
Spacer()
Image(systemName: "checkmark").foregroundColor(MXColor.system)
}.padding(.vertical, 11)
.padding(.horizontal, 16)
}
}
}
I want to show this modal not in full height, but to make it wrap content (so, for example if I have 2 elements it should fill only quater of screen and if there are 100 items they fill the whole height). For this purpose I created the following modifier:
struct AdaptiveModalModifier<T: View>: ViewModifier {
let sheetContent: () -> T
@Binding var isPresented: Bool
@State private var size: CGSize = .zero
func body(content: Content) -> some View {
if #available(iOS 16.0, *) {
content.sheet(isPresented: $isPresented) {
sheetContent().background(GeometryReader { proxy in
Color.clear.onAppear { size = proxy.size }
}).presentationDetents([.height(size.height)])
}
} else {
/// some logic here
}
}
}
So, this modifier just calculates the height of content and sets it to detents. But there's the issue with the ScrollView, that it fills the full height by default in my case (here's the screenshot) (red is the background of ScrollView)
I tried to add VStack into GeometryReader to check it's size and set it to ScrollView, but it returns 10.0 in my case (I don't know, how this value is calculated, but it seems to be wrong).
Can you please help me to set the ScrollView height the same as child's content? Thanks in advance for any help!