View-based NSOutlineView without NIB?

后端 未结 3 1552
难免孤独
难免孤独 2020-12-31 21:44

NSOutlineView is a subclass of NSTableView. And currently, NSTableView supports two implementations.

  • Cell-based.
相关标签:
3条回答
  • 2020-12-31 22:01

    If you follow the example in SidebarDemo, they use a subclass of NSTableCellView for the detail rows. In order to emulate the InterfaceBuilder mojo, you can hook everything together in the constructor. The rest is the same as the demo (see 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];
      ...
    
    0 讨论(0)
  • 2020-12-31 22:24

    In addition to @jeberle 's answer, I need to note something more.

    • The key to keep the text-field and image-view is adding them as subviews of the NSTableCellView.

    • Set NSTableView.rowSizeStyle to a proper value (non-Custom which is default value) to make the table-view layout them automatically. Otherwise, you have to layout them completely yourself.

    • Do not touch frame and autoresizing stuffs if you want to use predefined NSTableViewRowSizeStyle value. Otherwise, the layout might be broken.

    • You can adjust row-height by providing private func outlineView(outlineView: NSOutlineView, heightOfRowByItem item: AnyObject) -> CGFloat delegate method. Setting NSTableView.rowHeight is not a good idea because it needs NSTableView.rowSizeStyle set to Custom which will turn off cell text/image layout management provided by default.

    • You can reuse row/cell views by settings NSView.identifier property. (example)

    0 讨论(0)
  • 2020-12-31 22:26

    Here's @jeberle's code re-written in Swift 4 (five years later!):

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

    Edit: I found a link (that will inevitably rot away – it was last revised in 2011) to Apple's SidebarDemo that @jeberle based his code on.

    0 讨论(0)
提交回复
热议问题