NSOutlineView на основе представления без NIB?
NSOutlineView
это подкласс NSTableView
, И в настоящее время NSTableView
поддерживает две реализации.
- Клеточная.
- Просмотр основе.
Чтобы сделать боковую панель в стиле OSX 10.8 Finder (с автоматическим стилем серых значков), необходимо использовать табличное представление на основе вида со стилем выделения списка источников.
С NIB это типичная работа. Ничего сложного. (см. SidebarDemo) Но я хочу избежать любых NIB или Интерфейсного Разработчика. Я хочу сделать боковую панель чисто программно.
В этом случае у меня большая проблема. AFAIK, нет способа предоставить вид прототипа для конкретной ячейки. Когда я открою .xib
файл, я вижу <tableColumn>
содержит <prototypeCellViews>
, И это указывает, какое представление будет использоваться для столбца. Я не могу найти, как установить это программно с помощью публичного API.
В качестве обходного пути я попытался сделать ячейку вручную, используя -[NSTableView makeViewWithIdentifier:owner:]
а также -[NSTableView viewAtColumn:row:makeIfNecessary:]
, но ни один из них не возвращает представление экземпляра. Я создал NSTableCellView
, но у него нет экземпляров вида изображения и текстового поля. И я также попытался установить их, но поля помечены как assign
поэтому экземпляры немедленно освобождаются. Я пытался сохранить это, заставляя их удерживать, но это не работает. NSTableView
не управляет ими, поэтому я уверен, что табличному представлению не нравится моя реализация.
Я считаю, что есть свойство для установки этого прототипа для столбца. Но я не могу их найти. Где я могу найти свойство и сделать системный дефолт NSOutlineView
со стилем списка источников программно?
3 ответа
Если вы последуете примеру в SidebarDemo
они используют подкласс NSTableCellView
для подробных строк. Чтобы эмулировать moj InterfaceBuilder, вы можете соединить все вместе в конструкторе. Остальное так же, как демо (см. outlineView:viewForTableColumn:item:
).
@interface SCTableCellView : NSTableCellView
@end
@implementation SCTableCellView
- (id)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
[self setAutoresizingMask:NSViewWidthSizable];
NSImageView* iv = [[NSImageView alloc] initWithFrame:NSMakeRect(0, 6, 16, 16)];
NSTextField* tf = [[NSTextField alloc] initWithFrame:NSMakeRect(21, 6, 200, 14)];
NSButton* btn = [[NSButton alloc] initWithFrame:NSMakeRect(0, 3, 16, 16)];
[iv setImageScaling:NSImageScaleProportionallyUpOrDown];
[iv setImageAlignment:NSImageAlignCenter];
[tf setBordered:NO];
[tf setDrawsBackground:NO];
[[btn cell] setControlSize:NSSmallControlSize];
[[btn cell] setBezelStyle:NSInlineBezelStyle];
[[btn cell] setButtonType:NSMomentaryPushInButton];
[[btn cell] setFont:[NSFont boldSystemFontOfSize:10]];
[[btn cell] setAlignment:NSCenterTextAlignment];
[self setImageView:iv];
[self setTextField:tf];
[self addSubview:iv];
[self addSubview:tf];
[self addSubview:btn];
return self;
}
- (NSButton*)button {
return [[self subviews] objectAtIndex:2];
}
- (void)viewWillDraw {
[super viewWillDraw];
NSButton* btn = [self button];
...
Вот код @jeberle, переписанный в Swift 4 (пять лет спустя!):
class ProgrammaticTableCellView: NSTableCellView {
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
self.autoresizingMask = .width
let iv: NSImageView = NSImageView(frame: NSMakeRect(0, 6, 16, 16))
let tf: NSTextField = NSTextField(frame: NSMakeRect(21, 6, 200, 14))
let btn: NSButton = NSButton(frame: NSMakeRect(0, 3, 16, 16))
iv.imageScaling = .scaleProportionallyUpOrDown
iv.imageAlignment = .alignCenter
tf.isBordered = false
tf.drawsBackground = false
btn.cell?.controlSize = .small
// btn.bezelStyle = .inline // Deprecated?
btn.cell?.isBezeled = true // Closest property I can find.
// btn.cell?.setButtonType(.momentaryPushIn) // Deprecated?
btn.setButtonType(.momentaryPushIn)
btn.cell?.font = NSFont.boldSystemFont(ofSize: 10)
btn.cell?.alignment = .center
self.imageView = iv
self.textField = tf
self.addSubview(iv)
self.addSubview(tf)
self.addSubview(btn)
}
required init?(coder decoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var button: NSButton {
get {
return self.subviews[2] as! NSButton
}
}
}
Изменить: я нашел ссылку (которая неизбежно сгниет - в последний раз она была изменена в 2011 году) на Apple SidebarDemo, на которой @jeberle основывал свой код.
В дополнение к ответу @jeberle мне нужно отметить кое-что еще.
Ключ к тому, чтобы сохранить текстовое поле и представление изображения, добавляет их как подпредставления
NSTableCellView
,Задавать
NSTableView.rowSizeStyle
в надлежащее значение (неCustom
который является значением по умолчанию), чтобы сделать их табличное представление автоматически. В противном случае, вы должны макетировать их самостоятельно.Не трогай
frame
а такжеautoresizing
вещи, если вы хотите использовать предопределенныеNSTableViewRowSizeStyle
значение. В противном случае макет может быть нарушен.Вы можете настроить высоту строки, предоставив
private func outlineView(outlineView: NSOutlineView, heightOfRowByItem item: AnyObject) -> CGFloat
метод делегата. настройкаNSTableView.rowHeight
не очень хорошая идея, потому что это нужноNSTableView.rowSizeStyle
установлен вCustom
который отключит управление текстовым / графическим макетом ячейки по умолчанию.Вы можете повторно использовать представления строк / ячеек в настройках
NSView.identifier
имущество. ( пример)