I'm having trouble putting a List inside a sheet on macOS. The sheet size doesn't expand for the List at all, and the whole view is only as large as the "Done" button. Is there any way to get this to work properly similar to the iOS screenshot?
Here is my minimal example code:
import SwiftUI
struct ContentView: View {
@State var isPresented = false
var stuffs = ["stuff 0", "stuff 1", "stuff 3"]
var body: some View {
VStack {
Button("Show Sheet") {
isPresented = true
}
}
.padding()
.sheet(isPresented: $isPresented) {
Button("Done") {
isPresented = false
}
List {
ForEach(stuffs, id: \.self) { stuff in
Text(stuff)
}
}
// Adding a hardcoded frame size fixes it, but I'd prefer not to do that if possible so that it adapts to window sizes better.
// .frame(minWidth: 300, minHeight: 300)
}
}
}
I am hoping to not have to hard code a frame size. It does work better if I add a .frame(minWidth: 300, minHeight: 300)
view modifier to the List, but I'd prefer not to do that if possible so that it adapts to window sizes better.
Commenting out the List
view and just having the inner ForEach
also works as expected, but in the real app I want to make use of List
features.
I was expecting it to size itself automatically based on the content to something sensible.
This is something that comes with native macOS development compared to iOS or iPadOS.
On iPhone and iPadOS, sheets have an intrinsic minimum frame size. List
will expand to fill whatever it's given. However by default on macOS, sheets depend on their contents to determine how large they should be. So when List
doesn't "push out" the frame by itself, you end up with a small view.
So in this case, using .frame(minWidth:minHeight:)
is exactly the right thing to do.
If you're building a multiplatform target that also wants to serve iOS and/or iPadOS, you can make the frame conditional:
.sheet(isPresented: $isPresented) {
// I recommend providing a single view to `.sheet, with children
// (it makes extracting your sheet to a separate view so much easier)
VStack {
// ... contents here
}
#if os(macOS)
.frame(minWidth: 300, minHeight: 300)
#endif
}