Highlighting a NSMenuItem with a custom view?

早过忘川 提交于 2020-01-22 05:33:19

问题


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 (including selectors and highlighting) but as soon as I add a custom view (setView:) no highlighting occurs.

CustomMenuItem *menuItem = [[CustomMenuItem alloc] initWithTitle:@"" action:@selector(openPreferences:) keyEquivalent:@""];
[menuItem foo];
[menuItem setTarget:self];
[statusMenu insertItem:menuItem atIndex:0];
[menuItem release];

And my foo method is:

- (void)foo {
  NSView *view = [[NSView alloc] initWithFrame:CGRectMake(5, 10, 100, 20)];
  [self setView:view];
}

If I remove the setView method, it will highlight.

I have searched and searched and cannot find a way of implementing/enabling this.

Edit

I implemented highlight by following the code in this question in my NSView SubClass:

An NSMenuItem's view (instance of an NSView subclass) isn't highlighting on hover

#define menuItem ([self enclosingMenuItem])

- (void) drawRect: (NSRect) rect {
    BOOL isHighlighted = [menuItem isHighlighted];
    if (isHighlighted) {
        [[NSColor selectedMenuItemColor] set];
        [NSBezierPath fillRect:rect];
    } else {
        [super drawRect: rect];
    }
}

回答1:


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.




回答2:


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);
}



回答3:


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.




回答4:


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.)



来源:https://stackoverflow.com/questions/6054331/highlighting-a-nsmenuitem-with-a-custom-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!