I have created a simple NSStatusBar with a NSMenu set as the menu. I have also added a few NSMenuItems to this menu, which work fine (
If you're adding a view to a menu item, that view has to draw the highlight itself. You don't get that for free, I'm afraid. From the Menu Programming Topics:
A menu item with a view does not draw its title, state, font, or other standard drawing attributes, and assigns drawing responsibility entirely to the view.
Update for 2019:
class CustomMenuItemView: NSView {
private var effectView: NSVisualEffectView
override init(frame: NSRect) {
effectView = NSVisualEffectView()
effectView.state = .active
effectView.material = .selection
effectView.isEmphasized = true
effectView.blendingMode = .behindWindow
super.init(frame: frame)
addSubview(effectView)
effectView.frame = bounds
}
required init?(coder decoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ dirtyRect: NSRect) {
effectView.isHidden = !(enclosingMenuItem?.isHighlighted ?? false)
}
}
Set one of those to your menuItem.view.
(Credit belongs to Sam Soffes who helped me figure this out and sent me almost that code verbatim.)
Yes, as mentioned earlier you must draw it yourself. I use AppKit's NSDrawThreePartImage(…) to draw, and also include checks to use the user's control appearance (blue or graphite.) To get the images, I just took them from a screenshot (if anyone knows a better way, please add a comment.) Here's a piece of my MenuItemView's drawRect:
// draw the highlight gradient
if ([[self menuItem] isHighlighted]) {
NSInteger tint = [[NSUserDefaults standardUserDefaults] integerForKey:@"AppleAquaColorVariant"];
NSImage *image = (AppleAquaColorGraphite == tint) ? menuItemFillGray : menuItemFillBlue;
NSDrawThreePartImage(dirtyRect, nil, image, nil, NO,
NSCompositeSourceOver, 1.0, [self isFlipped]);
}
else if ([self backgroundColor]) {
[[self backgroundColor] set];
NSRectFill(dirtyRect);
}
EDIT
Should have defined these:
enum AppleAquaColorVariant {
AppleAquaColorBlue = 1,
AppleAquaColorGraphite = 6,
};
These correspond to the two appearance options in System Preferences. Also, menuItemFillGray & menuItemFillBlue are just NSImages of the standard menu item fill gradients.
Here's a rather less long-winded version of the above. It's worked well for me. (backgroundColour is an ivar.)
- (void)drawRect:(NSRect)rect
{
if ([[self enclosingMenuItem] isHighlighted]) {
[[NSColor selectedMenuItemColor] set];
} else if (backgroundColour) {
[backgroundColour set];
}
NSRectFill(rect);
}