如何检测NSView或其父级NSWindow的活动外观?

7
所有本地控件在其父窗口处于活动或非活动状态时均具有不同的外观。我们应该如何检查自定义组件的此状态,例如在呈现按钮单元格时?我们可以检查controlView.window的属性,例如isMainWindow和isKeyWindow,但它们并不覆盖所有情况。例如,如果您在桌面上打开应用程序的一个窗口并在全屏空间中打开另一个窗口,则根据公共API,只能有一个窗口是关键或主要的。但是,标准控件似乎在两个空间中都呈现为活动状态:请注意,Safari窗口中的工具栏按钮均呈现为活动状态。我们如何实现相同的行为?

你能否也检查窗口的全屏状态? - Mattie
@Mattie 我也检查了这个,但它在分屏全屏模式下不起作用,而且当你从全屏空间向桌面滑动时也是如此 ‍♂️ - Vadim
@Vadim 使用 Xcode 连接到 Safari 并使用 lldb [NSApp windows]... 来探索它们所做的事情。附注:使用正确标题过滤窗口。使用 hopper 检查源代码...(PrivateFrameworks/Safari.framework)-> 其中有许多好看的 Objective-C 代码。 - Marek H
1
@MarekH 不太确定你的意思。调试活动窗口几乎是不可能的,因为你需要在应用程序之间切换。我敢打赌Safari使用了一个名为NSWindow.hasActiveAppearance的私有API。 - Vadim
1
似乎NSWindow.hasActiveAppearance覆盖了所有情况。但是该属性不符合KVC,因此我们需要找到一个私有通知或使用计时器来获取更新。 - Jonny
显示剩余7条评论
2个回答

2

幸运的是,SwiftUI允许从环境中继承一个新的神奇属性:

/// Window state.
@Environment(\.controlActiveState)
var windowState: ControlActiveState

这是官方提供的解决方案。祝好运!


1
这并不包括一种情况,即1. 使您的窗口处于活动状态但不是全屏状态;2. 切换到全屏应用程序;3. 使用Command-Tab切换到同一空间中具有您活动窗口的另一个应用程序-> controlActiveState 在您的窗口不再处于活动状态时仍保持在“键”状态。 - Jonny

0
我在 Swift 5 中找到了这个解决方案(使用 NSButton 替代 NSView)。
class SomeView: NSButton {

    init() {
        super.init(frame: NSRect())
        self.isBordered = false

        // Setting `contentTintColor` can trigger `updateLayer()` when window's active state has changed
        self.contentTintColor = .labelColor
    }

    required init?(coder: NSCoder) {
        fatalError()
    }
    
    // Update view's appearance here
    override func updateLayer() {
        super.updateLayer()
        self.layer?.opacity = (self.window?.isMainWindow ?? false) ? 1 : 0.5
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接