Сначала получает события mouseEntered: и mouseExited: , вам необходимо настроить прямоугольник отслеживания, используя NSTrackingArea .
Я бы начал с подкласс NSTableRowView , который перезаписывает setFrame: , обеспечивая обновление прямоугольника отслеживания при изменении размера представления:
@interface TableRowView : NSTableRowView {
NSBox *_box;
NSTrackingArea *_trackingArea;
}
@property (weak) id owner;
@property (copy) NSDictionary<id, id> *userInfo;
@property (nonatomic) CGFloat indentation;
@property (nonatomic) BOOL indentationMarkerHidden;
@end
@implementation TableRowView
- (void)setFrame:(NSRect)frame
{
[super setFrame:frame];
if (_trackingArea) {
[self removeTrackingArea:_trackingArea];
}
_trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:NSTrackingMouseEnteredAndExited|NSTrackingActiveInKeyWindow owner:[self owner] userInfo:[self userInfo]];
[self addTrackingArea:_trackingArea];
}
@end
Чтобы использовать NSTableRowView подкласс, реализуйте сообщения NSOutlineViewDelegate следующим образом:
- (NSTableRowView *)outlineView:(NSOutlineView *)outlineView rowViewForItem:(id)item
{
TableRowView *view = [[TableRowView alloc] init];
view.owner = self;
view.userInfo = item;
return view;
}
Теперь вы готовы получать mouseEntered: и mouseExited: событий. Используйте NSOutlineView levelForItem: вместе с indentationPerLevel для вычисления позиции маркера NSBox .:
- (void)mouseEntered:(NSEvent *)event
{
id item = [event userData];
CGFloat indentation = [_outlineView levelForItem:item] * [_outlineView indentationPerLevel];
[self setIndentationMarker:indentation hidden:NO item:item];
}
- (void)mouseExited:(NSEvent *)event
{
id item = [event userData];
[self setIndentationMarker:0.0 hidden:YES item:item];
}
Теперь вы получаете подкласс NSTableRowView от rowViewAtRow: makeIfNeeded: и рекурсивно делаете то же самое для всех дочерних элементов в ваших данных:
- (void)setIndentationMarker:(CGFloat)indentation hidden:(BOOL)hidden item:(NSDictionary *)item
{
TableRowView *view = [_outlineView rowViewAtRow:[_outlineView rowForItem:item] makeIfNecessary:NO];
view.indentationMarkerHidden = hidden;
view.indentation = indentation;
for (NSMutableDictionary *child in [item objectForKey:@"children"]) {
[self setIndentationMarker:indentation hidden:hidden item:child];
}
}
Теперь разметьте NSBox подкласс NSTableRowView :
@implementation TableRowView
- (instancetype)init
{
self = [super init];
if (self) {
_indentationMarkerHidden = YES;
_box = [[NSBox alloc] init];
_box.boxType = NSBoxCustom;
_box.borderWidth = 0.0;
_box.fillColor = [NSColor tertiaryLabelColor];
_box.hidden = _indentationMarkerHidden;
[self addSubview:_box];
}
return self;
}
- (void)layout
{
[super layout];
NSRect rect = [self bounds];
rect.origin.x = _indentation + 7;
rect.size.width = 10;
_box.frame = rect;
}
- (void)setIndentation:(CGFloat)indentation
{
_indentation = indentation;
[self setNeedsLayout:YES];
}
- (void)setIndentationMarkerHidden:(BOOL)indentationMarkerHidden
{
if (_indentationMarkerHidden != indentationMarkerHidden) {
_indentationMarkerHidden = indentationMarkerHidden;
_box.hidden = indentationMarkerHidden;
}
}
@end
Этого достаточно, чтобы создать базовую c версию, как здесь:
Демонстрация маркера отступа NSOutlineView