如何让我的应用程序表现得像我正在使用 Swift 在运行时更改 Application is agent(UIElement)?

Posted

技术标签:

【中文标题】如何让我的应用程序表现得像我正在使用 Swift 在运行时更改 Application is agent(UIElement)?【英文标题】:How can I make my app behave like I'm changing Application is agent(UIElement) at runtime using Swift? 【发布时间】:2018-06-26 06:22:30 【问题描述】:

我正在编写一个 Mac 应用程序,它是菜单栏右侧的 NSPopoverApplication is agent(UIElement) 设置为 YES)。我允许用户通过单击并向下拖动来分离弹出框,这会将应用程序置于窗口内。这工作正常;但是,当应用程序被拖出菜单栏并变成一个窗口时,我希望我的应用程序的图标出现在 Dock 中,并在菜单栏的左侧显示应用程序特定的菜单,就好像Application is agent(UIElement) 设置为 NO。相反,当窗口关闭并且应用程序返回到菜单栏中的弹出窗口时,我希望我的应用程序的图标从 Dock 中消失,并且不再在菜单栏的左侧显示应用程序特定的菜单 (@987654327 @ 设置回 YES)。

来自this question,我了解到在运行时更改Application is agent(UIElement) 是不可能的。然而,给出的答案是在 Objective-C 中,最后一个函数似乎从 OS X 10.9 开始贬值。如何使我的应用程序具有与在运行时使用 Swift 更改 Application is agent(UIElement) 相同的行为?

我知道在windowDidBecomeMain 中会显示应用程序图标/菜单栏菜单,在windowWillClose 中会发生隐藏应用程序图标/菜单栏菜单。

谢谢。

【问题讨论】:

【参考方案1】:

我花了很多时间反复试验,但我终于弄明白了。而不是使用Application is agent(UIElement),而是使用NSApp.setActivationPolicy。现在这是我的代码。在 App Delegate 中:

var isWindow = false

class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate 

    let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
    let popover = NSPopover()

    func applicationDidFinishLaunching(_ aNotification: Notification) 
        // Insert code here to initialize your application

        NSApp.setActivationPolicy(.accessory)

        if let button = statusItem.button 
            button.image = NSImage(named: "StatusBarImage")
            button.action = #selector(togglePopover(_:))
        
        popover.contentViewController = MainViewController.loadController()
        popover.delegate = self
        popover.animates = false
        popover.behavior = .transient
    

    @objc func togglePopover(_ sender: Any?) 
        if popover.isShown == true 
            popover.performClose(sender)
         else if detachedWindowController.window!.isVisible 
            detachedWindowController.window?.setIsVisible(false)
            isWindow = true
         else if isWindow == true 
            detachedWindowController.window?.setIsVisible(true)
         else 
            if let button = statusItem.button 
                popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
            
        
    

    lazy var detachedWindowController: DetachedWindowController = 
        let detachedWindowController = DetachedWindowController(windowNibName: "DetachedWindowController")
        detachedWindowController.contentViewController = MainViewController.loadController()
        return detachedWindowController
    ()

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

    func detachableWindow(for popover: NSPopover) -> NSWindow? 
        return detachedWindowController.window
    

DetachedWindowController

class DetachedWindowController: NSWindowController, NSWindowDelegate 

    @IBOutlet var detachedWindow: NSWindow!

    override func windowDidLoad() 
        super.windowDidLoad()

        detachedWindow.delegate = self
    

    func windowWillClose(_ notification: Notification) 
        isWindow = false
        NSApp.setActivationPolicy(.accessory)
    

    func windowDidBecomeMain(_ notification: Notification) 
        if NSApp.activationPolicy() == .accessory 
            NSApp.setActivationPolicy(.regular)
        
    

【讨论】:

【参考方案2】:

此外,如果您在切换到常规后无法显示菜单和停靠图标,则可能需要执行以下操作。对于较旧的 Mac OS 版本,这绝对是必需的。

        // needed to activate menu
    NSArray *dockAppA = [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.loginwindow"];
    NSRunningApplication *dock = [dockAppA firstObject];
    [dock activateWithOptions:NSApplicationActivateIgnoringOtherApps];

    NSArray *dockAppB = [NSRunningApplication runningApplicationsWithBundleIdentifier:@"myAppBundleIdentifier"];
    NSRunningApplication *myApp = [dockAppB firstObject];
    [myApp activateWithOptions:NSApplicationActivateIgnoringOtherApps];

【讨论】:

以上是关于如何让我的应用程序表现得像我正在使用 Swift 在运行时更改 Application is agent(UIElement)?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Linux 中获取箭头键并在键盘上输入键以表现得像 Windows 7

BindingList<T>.Sort() 表现得像 List<T>.Sort()

如何在 Swift 中将触摸事件发送到 nextResponder

如何使 Recycler View 表现得像 PlayStore Recycler Views

如何让数据网格表现得像 ctrl 键处于活动状态?

为啥 CUDA 内存复制速度表现得像这样,一些恒定的驱动程序开销?