如何仅使用 SwiftUI 从@main App 访问 NSWindow?

Posted

技术标签:

【中文标题】如何仅使用 SwiftUI 从@main App 访问 NSWindow?【英文标题】:How to access NSWindow from @main App using only SwiftUI? 【发布时间】:2020-08-16 02:57:26 【问题描述】:

在这个answer,解决方案适用于 Scene plus swiftUI。

但是使用 @main 之类的:

@main
struct MyApp: App 
    @StateObject private var model = MyModel()
    
    var body: some Scene 
        WindowGroup 
            Router 
                AppContent()
            .environmentObject(self.model)
        
    

我也尝试通过使用来获取主窗口

var window: NSWindow? 
        let window = NSApplication.shared.mainWindow
        return window
    

尽管如此,mainWindow 总是返回 nil

更新:

我需要NSWindow,因为需要符合ASWebAuthenticationPresentationContextProviding,它必须返回NSWindow。基本上,我正在尝试做类似的事情:

LoginView(store: AuthStore(window: window))

其中AuthStore 使用AuthenticationServices 执行身份验证。

【问题讨论】:

你没有显示为什么/在哪里需要窗口,你会介绍吗? @Asperi 感谢您的亮点,我更新了问题,如果您现在想看看并提供一些反馈,我将不胜感激 【参考方案1】:

基本上,我正在尝试做类似的事情:

LoginView(store: AuthStore(window: window))

这是一个可能的方法的演示(带有一些复制的实体)

class AuthStore 
    var window: NSWindow

    init(window: NSWindow) 
        self.window = window
    


struct DemoWindowAccessor: View 
    @State private var window: NSWindow?   // << detected in run-time so optional
    var body: some View 
        VStack 
            if nil != window 
                LoginView(store: AuthStore(window: window!))    // << usage
            
        .background(WindowAccessor(window: $window))
    


struct WindowAccessor: NSViewRepresentable 
    @Binding var window: NSWindow?

    func makeNSView(context: Context) -> NSView 
        let view = NSView()
        DispatchQueue.main.async 
            self.window = view.window   // << right after inserted in window
        
        return view
    

    func updateNSView(_ nsView: NSView, context: Context) 


struct LoginView: View 
    let store: AuthStore

    var body: some View 
        Text("LoginView with Window: \(store.window)")
    

【讨论】:

谢谢!它就像一个魅力 \o/ 很棒的建议? 在找到您非常有用的示例之前,我问了几乎相同的问题 (***.com/a/65401530/792406),该示例效果非常好,因此感谢您发布。 出于好奇,这种方法是使用新的 SwiftUI 生命周期访问 NSWindow 实例的唯一方法吗?我需要在我的场景中更改窗口的外观和行为。【参考方案2】:

方法很多,但有一个陷阱阅读完整答案

NSApplication.shared.keyWindow, NSApp.keyWindow, 
NSApp.mainWindow, 

有时,这些可能会返回 nil,尤其是在启动期间或应用处于非活动状态时

我认为这是因为从 Appkit 方面设置这些属性可能不是即时的

最好是访问所有窗口

     NSApp.windows.first

这将返回所有窗口,但顺序不可预测

如果您有多个窗口,您可以进行进一步过滤以找到所需的窗口,但这种方法避免了其他方法返回 nil 的疯狂行为

【讨论】:

以上是关于如何仅使用 SwiftUI 从@main App 访问 NSWindow?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:当我按下按钮时如何打开(App-)电话设置?

如何从 SwiftUI 中的 Bundle 中的有效路径或 URL 将图像加载到 Image()?

SwiftUI 中如何获取任意视图触摸位置(全局或局部)的坐标

SwiftUI 中如何获取任意视图触摸位置(全局或局部)的坐标

SwiftUI 中如何获取任意视图触摸位置(全局或局部)的坐标

SwiftUI 按钮作为 EditButton