问题
I have been working on a NSStatusItem user agent that adds a NSView subclass as a subview of NSStatusItem.button to provide animated icons.
When left clicking on the icon, there is a noticeable opaque border around the view.
The view subclass's init reads:
- (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;
}
The view, StatusView, is added by a controller to the NSStatusBarItem's button:
self.statusItem.highlightMode = YES;
[self.statusItem.button addSubview:self.statusView];
Here is what it looked like after a left mouse down:

Not really the polished look I was hoping for.
回答1:
I spent a lot of time reading the documentation trying to figure out how get rid of that border. I checked for opacity in my view, layer and sublayers. I set background colors to clear. I messed with alpha. I re-wrote my view without layers. Nothing could get rid of that opaque bound and I was about ready to throw in the towel and provide my content via a NSImage with setTemplate:YES.
As a last ditch effort to understand what was happening, I wrote a short method to traverse the view's hierarchy looking for the view that was opaque:
- (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];
}
}
I found the property opaqueAncestor while poring over the documentation for NSView and figured that might be a good place to start looking.
Called from my NSView subclass's drawLayer:inContext: method thusly.
[self displayViewInfo:self.opaqueAncestor];
The output (with timestamp info trimmed) looked like :
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>
The opaqueAncestor of StatusView turned out to be the root view for the hierarchy and all the subviews were reporting not opaque. I added the allowVibrancy check after a few mutations of the method. I found it interesting that the superviews of StatusView were allowing vibrancy and my view was not. The documentation on the property allowVibrancy was vaguely promising, so I added this to my view:
- (BOOL)allowVibrancy { return YES; }
The result speaks for itself:

Hopefully this tale of woe and redemption will save somebody some time; it sure had me baffled.
来源:https://stackoverflow.com/questions/30005185/nsview-added-to-nsstatusitem-button-has-an-opaque-border