NSOutlineView на основе представления без NIB?

NSOutlineView является подклассом NSTableView. В настоящее время NSTableView поддерживает две реализации.

  • На основе ячеек.
  • На основе просмотра.

Чтобы сделать боковую панель в стиле OSX 10.8 Finder (с автоматическим оформлением серого значка), необходимо использовать табличное представление на основе представления со стилем выделения исходного списка.

С NIB это типичная работа. Ничего сложного. (см. SidebarDemo) Но я хочу избежать использования NIB или Interface Builder. Хочу сделать боковую панель чисто программно.

В этом случае у меня большая проблема. AFAIK, нет возможности предоставить представление прототипа для конкретной ячейки. Когда я открываю .xib файл, я вижу, что <tableColumn> содержит <prototypeCellViews>. И это указывает, какое представление будет использоваться для столбца. Я не могу найти, как установить это программно с помощью общедоступного API.

В качестве обходного пути я попытался создать ячейку вручную, используя -[NSTableView makeViewWithIdentifier:owner:] и -[NSTableView viewAtColumn:row:makeIfNecessary:], но ни один из них не возвращает экземпляр представления. Я создал NSTableCellView, но у него нет экземпляров просмотра изображений и текстовых полей. И я также попытался установить их, но поля помечены как assign, поэтому экземпляры немедленно освобождаются. Я пытался сохранить это, заставляя их удерживать, но это не сработало. NSTableView не управляет ими, поэтому я уверен, что этому табличному представлению не нравится моя реализация.

Я считаю, что есть свойство установить это представление прототипа для столбца. Но я не могу их найти. Где я могу найти свойство и программно сделать NSOutlineView системный параметр по умолчанию со стилем списка источников?


person eonil    schedule 19.10.2013    source источник
comment
Документация NSOutlineView обычно скудная и неполная.   -  person uchuugaka    schedule 26.11.2013


Ответы (3)


Если вы следуете примеру в SidebarDemo, они используют подкласс NSTableCellView для строк деталей. Чтобы эмулировать моджо 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];
  ...
person jeberle    schedule 26.11.2013
comment
Ага. По сути, предоставьте свой класс просмотра. Сообщите делегату о вашем классе представления. Убедитесь, что ваш класс представления знает, как выровнять себя и свои подпредставления по мере их добавления и удаления из OutlineView. Это не упрощает просмотр схемы. Они по-прежнему PITA. - person uchuugaka; 26.11.2013
comment
Это работает! Магия! Ключ к тому, чтобы это работало, - это добавление текстовых представлений и изображений в качестве подвидов NSTableCellView. Также я вообще не должен трогать фреймы и автоизменения размеров. NSOutlineView не разместит их должным образом, если я их коснусь. - person eonil; 12.10.2014

Вот код @ 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 году) на SidebarDemo, на котором @jeberle основал свой код.

person Jamie Birch    schedule 07.08.2018

В дополнение к ответу @jeberle мне нужно отметить еще кое-что.

  • Ключом к сохранению текстового поля и просмотра изображения является добавление их в качестве подпредставлений NSTableCellView.

  • Установите NSTableView.rowSizeStyle на правильное значение (не Custom, которое является значением по умолчанию), чтобы сделать макет табличного представления автоматически. В противном случае вам придется полностью разметить их самостоятельно.

  • Не прикасайтесь к материалам frame и autoresizing, если хотите использовать предопределенное значение NSTableViewRowSizeStyle. В противном случае макет может быть нарушен.

  • Вы можете настроить высоту строки, предоставив private func outlineView(outlineView: NSOutlineView, heightOfRowByItem item: AnyObject) -> CGFloat метод делегата. Установка NSTableView.rowHeight не является хорошей идеей, потому что для этого нужно NSTableView.rowSizeStyle установить значение Custom, что отключит управление макетом текста / изображения ячеек, предусмотренное по умолчанию.

  • Вы можете повторно использовать представления строк / ячеек, установив свойство NSView.identifier. ( person eonil    schedule 12.10.2014

comment
Спасибо за ссылку на вашу суть. Мне нужно было видеть, что NSView.identifier устанавливается, когда makeView () возвращает nil, чтобы моя таблица без пера работала. - person WeakPointer; 12.11.2017