I have an AppKit app where I'd like to embed a SwiftUI view using NSHostingView. The SwiftUI view is based on a VStack, and looks like this:
struct IPReportView: View {
//This is rather long, but contains some lazy grid views that result in an overall view
//with a fixed width and height.
}
struct IPReportDetailView: View {
@Binding var report: IPReportDocument?
var body: some View {
if let selectedReport = report {
VStack(spacing: 20.0) {
Text(selectedReport.title)
.font(.headline)
IPReportView(reportDocument: selectedReport)
Spacer()
}
} else {
IPEmptyMessageView(header: "No report selected")
}
}
}
//Eventually there'll be a Split View but I just need to get the basics working first
struct IPReportListSplitView: View {
@ObservedObject var reportListViewModel: IPReportListViewModel
@State var selectedReport: IPReportDocument?
var body: some View {
IPReportDetailView(report: $selectedReport)
}
}
The setup for the hosting view looks like so:
//BWViewController is an NSViewController subclass. The calling code inserts
//IPReportListViewController's view with constraints to pin its sides to all four
//sides of its superview
class IPReportListViewController: BWViewController {
lazy var reportListViewModel: IPReportListViewModel = IPReportListViewModel(reports: IPReportDocument.allStoredReports())
override func loadView() {
let reportListMainView = IPReportListSplitView(reportListViewModel: self.reportListViewModel, selectedReport: self.reportListViewModel.reports.first)
let hostingView = NSHostingView(rootView: reportListMainView)
hostingView.translatesAutoresizingMaskIntoConstraints = false
hostingView.layer?.borderWidth = 1.0
hostingView.layer?.borderColor = NSColor.green.cgColor
self.view = hostingView
}
}
When I run this, the window I get looks like this. Note the green border that denotes the bounds of the NSHostingView. What I'm trying to achieve is have the NSHostingView take up the entire bounds of its superview, and have the report view aligned to the top of the NSHostingView.

What I would like to find is some way to have the IPReportDetailView declare that it wants as much height as the NSHostingView will offer it, rather than having the NSHostingView shrink its height to match the intrinsic content size of the IPReportDetailView. The normal stack to have a stack eat up additional space is to add a Spacer(), which I've done here, but in the context of a hosting view that doesn't seem to do anything. I've also tried appending .frame(maxHeight: .infinity) in various places, but to no effect.
I know the NSHostingView will take up the whole content area in other cases, e.g. if I set the report binding to nil and it shows IPEmptyMessageView, which is basically a Color(.clear) with a text overlay that does take up the whole content area. Ultimately the hosted SwiftUI View will be a HSplitView, with a SwiftUI List of reports on the left and the report detail on the right, so I don't want to "solve" the problem by adding space with AppKit stuff around the NSHostingView. Any ideas are appreciated.
NSHostingViewresize with its parent by setting the max width and height for the SwiftUI view to infinity, using.frame(maxWidth: .infinity, maxHeight: .infinity).