使用自定义视图突出显示NSMenuItem?

时间:2011-05-19 05:45:48

标签: objective-c cocoa nsmenuitem

我创建了一个简单的NSStatusBar,其中NSMenu设置为菜单。我还在这个菜单中添加了一些NSMenuItems,它可以正常工作(包括选择器和突出显示),但是一旦我添加自定义视图(setView :),就不会突出显示。

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

我的foo方法是:

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

如果我删除了setView方法,它将突出显示。

我搜索并搜索过,无法找到实现/启用此功能的方法。

修改

我在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];
    }
}

4 个答案:

答案 0 :(得分:10)

以上是一个相当不太冗长的版本。它对我有用。 (backgroundColour是一个ivar。)

- (void)drawRect:(NSRect)rect
{
    if ([[self enclosingMenuItem] isHighlighted]) {
        [[NSColor selectedMenuItemColor] set];
    } else if (backgroundColour) {
        [backgroundColour set];
    }
    NSRectFill(rect);
}

答案 1 :(得分:6)

如果要向菜单项添加视图,则该视图必须自己绘制突出显示。你不是免费得到的,我害怕。来自Menu Programming Topics

  

带有视图的菜单项不会绘制其标题,状态,字体或其他标准绘图属性,并将绘图责任完全分配给视图。

答案 2 :(得分:3)

是的,如前所述,你必须自己画画。我使用AppKit的NSDrawThreePartImage(...)进行绘制,还包括使用用户控件外观(蓝色或石墨)的检查。为了获取图像,我只是从截图中取出它们(如果有人知道更好的方法,请添加评论。)这是我的MenuItemView的一个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);
}

修改

应该定义这些:

enum AppleAquaColorVariant {
    AppleAquaColorBlue = 1,
    AppleAquaColorGraphite = 6,
};

这些对应于“系统偏好设置”中的两个外观选项。另外,menuItemFillGray& menuItemFillBlue只是标准菜单项填充渐变的NSImages。

答案 3 :(得分:0)

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

将其中之一设置为您的menuItem.view

(信用属于Sam Soffes,他帮助我弄清了这个问题,并几乎逐字向我发送了该代码。)