基于“源列表”NSOutlineView的视图自定义选择样式

3
我正在使用基于视图的NSOutlineView,它的selectionHighlightStyle设置为NSTableViewSelectionHighlightStyleSourceList
我想要覆盖某些行的选择样式(背景),并绘制不同的颜色/渐变。
到目前为止,我尝试创建自定义NSTableRowView,并通过outlineView:rowViewForItem:返回它。我验证了我的自定义行视图是由大纲视图代理创建和返回的。然而,我在自定义行视图中重写的任何方法都没有被调用。
我尝试覆盖drawBackgroundInRect:drawSelectionInRect:drawSeparatorInRect:甚至drawRect:。但这些方法从未被调用过。
我怀疑大纲视图在设置为源列表样式时执行了一些自定义“魔法”,但我没有在文档中找到任何指示自定义NSTableRowView不会在这种情况下被完全采用的内容。
3个回答

4

AppKit会在使用NSTableViewSelectionHighlightStyleSourceList时,为行视图添加单独的NSVisualEffectView以绘制背景中的自定义材料。我想出了以下解决方法,它不使用任何私有API,但如果苹果实现了其他突出显示行的方式,则可能会失效。

@class CustomHighlightRowSelectionView;
@interface CustomHighlightRowView : NSTableRowView

@property (nonatomic, strong) CustomHighlightRowSelectionView *selectionView;

@end

@interface CustomHighlightRowSelectionView : NSView

@property (nonatomic, getter=isEmphasized) BOOL emphasized;
@property (nonatomic, getter=isSelected) BOOL selected;

@end


@implementation CustomHighlightRowView

- (CustomHighlightRowSelectionView *)selectionView
{
    if (!_selectionView)
    {
        _selectionView = [[CustomHighlightRowSelectionView alloc] initWithFrame:NSZeroRect];
    }

    return _selectionView;
}

- (void)setEmphasized:(BOOL)emphasized
{
    [super setEmphasized:emphasized];
    self.selectionView.emphasized = emphasized;
}

- (void)setSelected:(BOOL)selected
{
    [super setSelected:selected];
    self.selectionView.selected = selected;
}

- (void)addSubview:(NSView *)aView positioned:(NSWindowOrderingMode)place relativeTo:(NSView *)otherView
{
    if (![aView isKindOfClass:[NSVisualEffectView class]])
    {
        [super addSubview:aView positioned:place relativeTo:otherView];
    }
    else
    {
        if (!self.selectionView.superview)
        {
            [super addSubview:self.selectionView positioned:place relativeTo:otherView];
            self.selectionView.frame = self.bounds;
        }
    }
}

- (void)setFrame:(NSRect)frame
{
    [super setFrame:frame];

    self.selectionView.frame = self.bounds;
}

- (void)setBounds:(NSRect)bounds
{
    [super setBounds:bounds];

    self.selectionView.frame = self.bounds;
}

@end

@implementation CustomHighlightRowSelectionView

- (void)setEmphasized:(BOOL)emphasized
{
    _emphasized = emphasized;
    [self setNeedsDisplay:YES];
}

- (void)setSelected:(BOOL)selected
{
    _selected = selected;
    [self setNeedsDisplay:YES];
}

- (void)drawRect:(NSRect)dirtyRect
{
    if (!self.selected)
    {
        return;
    }

    NSColor *fillColor = self.emphasized ? [NSColor alternateSelectedControlColor] : [NSColor secondarySelectedControlColor];
    [fillColor setFill];
    NSRectFill(dirtyRect);
}

@end

这应该是被接受的答案,它完美地工作! - sebastienhamel

1

您需要在NSTableRowView子类中覆盖-selectionHighlightStyle:

- (NSTableViewSelectionHighlightStyle)selectionHighlightStyle
{
    return NSTableViewSelectionHighlightStyleRegular;
}

那样,表格视图可以以源列表样式使用,但具有自定义的行选择。我想在我的项目中使用Yosemite下的源列表,但使用用户从系统偏好设置中选择的颜色。 编辑:我刚刚注意到这样做会导致单元格视图内的文本字段和图像视图出现类似边框的伪影,看起来非常奇怪和丑陋。

我刚刚注意到这样做会导致单元格视图内的文本字段和图像视图具有类似边框的瑕疵,看起来非常奇怪和丑陋。底线是 - 源列表样式的选择颜色无法调整。相反,我使用了常规样式,并手动设计了轮廓视图,使其看起来像源列表。注意:如果您的目标是Yosemite,并且您想要使用源列表时默认打开的半透明背景外观,则需要将轮廓视图嵌入NSVisualEffectView中。 - Toby
我知道可以使用NSTableViewSelectionHighlightStyleRegular并“伪造”源列表外观,但我宁愿使用非自定义选择样式,而不是自己实现所有源列表样式... - lemonmojo
我同意,使用本地语言编写通常更好、更优雅,但在这种情况下,恐怕你可能会运气不佳。找到一种修改/黑客轮廓视图以在源列表模式下具有自定义选择行的方法将比手动修改视图需要更长的时间。 - Toby

1

你是否正在使用Yosemite操作系统? 来自苹果文档 采用Yosemite中新UI的高级功能

当 selectionHighlightStyle == NSTableViewSelectionHighlightStyleSourceList • 选择现在是一种特殊的蓝色材料,可以在窗口后面混合 - 材料的尺寸和绘制不能定制

如果将其设置为NSTableViewSelectionHighlightStyleRegular并覆盖drawRect,则应该可以工作。


是的,我正在使用Yosemite,尽管我已经观看了您提到的WWDC会议,但似乎我错过了“材料大小和绘图无法自定义”的部分。如果我想要同时使用源列表样式并为多行自定义选择绘图,那么看来我运气不太好。 - lemonmojo
你想要移除蓝色的高亮吗?如果是的话,你可能会对这个感兴趣:https://dev59.com/bl8d5IYBdhLWcg3woDcZ#26990727 - Oskar
这绝对是有用的,我刚刚在我的应用程序的另一个部分中实现了这个。太棒了!然而,在这种特定情况下,我想要覆盖默认的蓝色高亮显示为完全不同的颜色/渐变。 - lemonmojo
在El Capitan中再次调用了drawSelectionInRect: - ylian
@ylian,你如何在El Capitan中调用drawSelectionInRect: - Harry Ng
对我来说,在El Captain中drawSelectionInRect没有被调用。 - Lubos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接