Сначала мне понравился ответ, данный @Asperi, но когда я попробовал его в своей среде, мне было трудно работать из-за необходимости знать представление root во время создания окна (следовательно, я не знаю окно в то время, когда я создаю root представление). Поэтому я последовал его примеру, но вместо значения среды я выбрал использование объекта среды. Это имеет почти такой же эффект, но мне было легче начать работать. Ниже приведен код, который я использую. Обратите внимание, что я создал обобщенный класс c, который создает NSWindowController с учетом представления SwiftUI. (Обратите внимание, что userDefaultsManager
- это еще один объект, который мне нужен в большинстве windows в моем приложении. Но я думаю, что если вы удалите эту строку плюс строку appDelegate
, вы получите решение, которое будет работать в значительной степени в любом месте.)
class RootViewWindowController<RootView : View>: NSWindowController {
convenience init(_ title: String,
withView rootView: RootView,
andInitialSize initialSize: NSSize = NSSize(width: 400, height: 500))
{
let appDelegate: AppDelegate = NSApplication.shared.delegate as! AppDelegate
let windowWrapper = NSWindowWrapper()
let actualRootView = rootView
.frame(width: initialSize.width, height: initialSize.height)
.environmentObject(appDelegate.userDefaultsManager)
.environmentObject(windowWrapper)
let hostingController = NSHostingController(rootView: actualRootView)
let window = NSWindow(contentViewController: hostingController)
window.setContentSize(initialSize)
window.title = title
windowWrapper.rootWindow = window
self.init(window: window)
}
}
final class NSWindowWrapper: ObservableObject {
@Published var rootWindow: NSWindow? = nil
}
Затем, на мой взгляд, где мне это нужно (чтобы закрыть окно в соответствующее время), моя структура начинается следующим образом:
struct SubscribeToProFeaturesView: View {
@State var showingEnlargedImage = false
@EnvironmentObject var rootWindowWrapper: NSWindowWrapper
var body: some View {
VStack {
Text("Professional Version Upgrade")
.font(.headline)
VStack(alignment: .leading) {
И в кнопке, где мне нужно закрыть окно, у меня есть
self.rootWindowWrapper.rootWindow?.close()
Это не так чисто, как мне хотелось бы (я бы предпочел, чтобы у меня было решение, в котором я просто сказал self.rootWindow?.close()
требует наличия класса-обертки), но это неплохо, и это позволяет мне создать объект rootView, прежде чем я создаю окно.