添加到 NSStatusItem 按钮的 NSView 有一个不透明的边框

NSView added to NSStatusItem button has an opaque border

我一直在开发一个 NSStatusItem 用户代理,它添加一个 NSView 子类作为 NSStatusItem.button 的子视图以提供动画图标。

左键单击图标时,视图周围有一个明显的不透明边框。

视图子类的初始化读取:

- (instancetype)initWithFrame:(NSRect )rect
{
    self = [super initWithFrame:rect];
    if ( self ) {
        self.wantsLayer = YES;
        self.layer.opaque = NO;
        [self.layer addSublayer:self.background];
        [self.layer addSublayer:self.foreground];
        [self.layer addSublayer:self.symbol];
    }
    return self;
}

视图 StatusView 由控制器添加到 NSStatusBarItem 的按钮:

    self.statusItem.highlightMode = YES;
    [self.statusItem.button addSubview:self.statusView];

这是按下鼠标左键后的样子:

并不是我所希望的精致外观。

我花了很多时间阅读文档试图弄清楚如何摆脱那个边界。我检查了视图、图层和子图层中的不透明度。我将背景颜色设置为清除。我搞砸了阿尔法。我重写了我的观点,没有层次。没有什么可以摆脱那个不透明的界限,我准备认输并通过带有 setTemplate:YES 的 NSImage 提供我的内容。

作为了解正在发生的事情的最后努力,我编写了一个简短的方法来遍历视图的层次结构以查找不透明的视图:

- (void)displayViewInfo:(NSView *)view
{
    NSLog(@"view %@\tisOpaque %d, vibrancy %d super %@",
          view,view.isOpaque,view.allowsVibrancy, view.superview);
    for (NSView *v in view.subviews){
         [self displayViewInfo:v];
    }
}

我在仔细阅读 NSView 的文档时发现了 属性 opaqueAncestor,并认为这可能是开始寻找的好地方。

从我的 NSView 子类的 drawLayer:inContext: 方法中调用。

[self displayViewInfo:self.opaqueAncestor];

输出(修剪了时间戳信息)看起来像:

view <NSNextStepFrame: 0x610000181380>   isOpaque 1, vibrancy 0 super (null)
view <NSVisualEffectView: 0x1006023e0>   isOpaque 0, vibrancy 1 super <NSNextStepFrame: 0x610000181380>
view <NSStatusBarButton: 0x600000161bc0> isOpaque 0, vibrancy 1 super <NSVisualEffectView: 0x1006023e0>
view <StatusView: 0x6000001a02a0>        isOpaque 0, vibrancy 0 super <NSStatusBarButton: 0x600000161bc0>

StatusView 的 opaqueAncestor 原来是层次结构的根视图,所有子视图都报告不是不透明的。在对该方法进行一些更改后,我添加了 allowVibrancy 检查。我发现有趣的是,StatusView 的超级视图允许充满活力,而我的视图则不然。 属性 allowVibrancy 上的文档含糊其辞,所以我将其添加到我的观点中:

- (BOOL)allowVibrancy { return YES; }

结果不言而喻:

希望这个关于灾难和救赎的故事能节省一些时间;这确实让我感到困惑。