macos - 如何在 SwiftUI 生命周期中显示 NSPopover?

标签 macos swiftui appdelegate nspopover

我试图通过单击按钮来显示可拆卸的 NSPopover,但我被卡住了。我跟着 tuts 如何显示 NSPopover 但它们都围绕着菜单栏应用程序。
我的 AppDelegate 看起来像这样

final class AppDelegate: NSObject, NSApplicationDelegate {
    var popover: NSPopover!
    
    func applicationDidFinishLaunching(_ notification: Notification) {
        let popover = NSPopover()
        let popoverView = PopoverView()
        
        popover.contentSize = NSSize(width: 300, height: 200)
        popover.contentViewController = NSHostingController(rootView: popoverView)
        popover.behavior = .transient
        
        self.popover = popover
    }
    
     func togglePopover(_ sender: AnyObject?) {
        self.popover.show(relativeTo: (sender?.bounds)!, of: sender as! NSView, preferredEdge: NSRectEdge.minY)
    }
}

最佳答案

这是一个可能的方法的简单演示 - 包装控制原生 NSPopover进入可表示的背景 View 。
注意:接下来将背景包装到 View 修改器中或/并使其更具可配置性取决于您。
使用 Xcode 13/macOS 11.5.1 准备和测试
demo

struct ContentView: View {
    @State private var isVisible = false
    var body: some View {
        Button("Test") {
            isVisible.toggle()
        }
        .background(NSPopoverHolderView(isVisible: $isVisible) {
            Text("I'm in NSPopover")
                .padding()
        })
    }
}

struct NSPopoverHolderView<T: View>: NSViewRepresentable {
    @Binding var isVisible: Bool
    var content: () -> T

    func makeNSView(context: Context) -> NSView {
        NSView()
    }

    func updateNSView(_ nsView: NSView, context: Context) {
        context.coordinator.setVisible(isVisible, in: nsView)
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(state: _isVisible, content: content)
    }

    class Coordinator: NSObject, NSPopoverDelegate {
        private let popover: NSPopover
        private let state: Binding<Bool>

        init<V: View>(state: Binding<Bool>, content: @escaping () -> V) {
            self.popover = NSPopover()
            self.state = state

            super.init()

            popover.delegate = self
            popover.contentViewController = NSHostingController(rootView: content())
            popover.behavior = .transient
        }

        func setVisible(_ isVisible: Bool, in view: NSView) {
            if isVisible {
                popover.show(relativeTo: view.bounds, of: view, preferredEdge: .minY)
            } else {
                popover.close()
            }
        }

        func popoverDidClose(_ notification: Notification) {
            self.state.wrappedValue = false
        }

        func popoverShouldDetach(_ popover: NSPopover) -> Bool {
            true
        }
    }
}

关于macos - 如何在 SwiftUI 生命周期中显示 NSPopover?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68688263/

相关文章:

macos - 如何在 OS X 上从 gethostname() 获得一致的结果?

python - 编译 Python 2.7.5 问题

core-data - SwiftUI ImagePicker 将 (Image -> UIImage --> Data) 保存到 Core Data

swift - FBSDKShareButton 成功发布链接,但返回应用程序时崩溃

swift - 如何使用静默推送通知按需更新用户位置? iOS

c++ - 跨平台宏定义

macos - Homebrew 不再 brew

ios - 如何使 SwiftUI 循环中的元素全屏显示?与 Apple 一样,当今的应用程序

SwiftUI,如何翻译带有计时器样式的文本?

ios - 等待 didFinishLaunchingWithOptions 中的服务操作和延迟后调用的 didRegisterForRemoteNotificationsWithDeviceToken