How to customize disclosure cell in view-based NSOutlineView

旧街凉风 提交于 2019-11-28 06:01:08
Monolo

This answer is written with OS X 10.7 in mind, for newer versions of OS X/macOS, refer to WetFish's answer

That method does not get called because it is only relevant for cell based outline views.

In a view based outline view, the disclosure triangle is a regular button in the row view of expandable rows. I don't know where it gets added, but it does, and NSView's didAddSubview: method handles exactly that situation of a view being added somewhere else.

Hence, subclass NSTableRowView, and override didAddSubview:, like this:

-(void)didAddSubview:(NSView *)subview
{
    // As noted in the comments, don't forget to call super:
    [super didAddSubview:subview];

    if ( [subview isKindOfClass:[NSButton class]] ) {
        // This is (presumably) the button holding the 
        // outline triangle button.
        // We set our own images here.
        [(NSButton *)subview setImage:[NSImage imageNamed:@"disclosure-closed"]];
        [(NSButton *)subview setAlternateImage:[NSImage imageNamed:@"disclosure-open"]];
    }
}

Of course, your outline view's delegate will have to implement outlineView:rowViewForItem: to return the new row view.

Despite the name, frameOfOutlineCellAtRow: of NSOutlineView still gets called for view based outline views, so for the positioning of your triangle, you might want to subclass the outline view and override that method, too.

WetFish

Solution 1:

Subclass NSOutlineView and override makeViewWithIdentifier:owner:

- (id)makeViewWithIdentifier:(NSString *)identifier owner:(id)owner {
    id view = [super makeViewWithIdentifier:identifier owner:owner];

    if ([identifier isEqualToString:NSOutlineViewDisclosureButtonKey]) {
        // Do your customization
    }

    return view;
}

For Source Lists use NSOutlineViewShowHideButtonKey.

Solution 2:

Interface Builder

The button is added to the column and the identifier set to NSOutlineViewDisclosureButtonKey.

Official documentation from NSOutlineView.h

/* The following NSOutlineView*Keys are used by the View Based NSOutlineView to create the "disclosure button" used to collapse and expand items. The NSOutlineView creates these buttons by calling [self makeViewWithIdentifier:owner:] passing in the key as the identifier and the delegate as the owner. Custom NSButtons (or subclasses thereof) can be provided for NSOutlineView to use in the following two ways:
 1. makeViewWithIdentifier:owner: can be overridden, and if the identifier is (for instance) NSOutlineViewDisclosureButtonKey, a custom NSButton can be configured and returned. Be sure to set the button.identifier to be NSOutlineViewDisclosureButtonKey.
 2. At design time, a button can be added to the outlineview which has this identifier, and it will be unarchived and used as needed.

 When a custom button is used, it is important to properly set up the target/action to do something (probably expand or collapse the rowForView: that the sender is located in). Or, one can call super to get the default button, and copy its target/action to get the normal default behavior.

 NOTE: These keys are backwards compatible to 10.7, however, the symbol is not exported prior to 10.9 and the regular string value must be used (i.e.: @"NSOutlineViewDisclosureButtonKey").
 */
APPKIT_EXTERN NSString *const NSOutlineViewDisclosureButtonKey NS_AVAILABLE_MAC(10_9); // The normal triangle disclosure button
APPKIT_EXTERN NSString *const NSOutlineViewShowHideButtonKey NS_AVAILABLE_MAC(10_9); // The show/hide button used in "Source Lists"

Swift2 version of @Monolo's answer:

override func didAddSubview(subview: NSView) {
    super.didAddSubview(subview)
    if let sv = subview as? NSButton {
        sv.image = NSImage(named:"icnArwRight")
        sv.alternateImage = NSImage(named:"icnArwDown")
    }
}

For Swift 4.2 macOS 10.14, @WetFish's answer can be implemented as follows:

class SidebarView: NSOutlineView {

  override func makeView(withIdentifier identifier: NSUserInterfaceItemIdentifier, owner: Any?) -> NSView? {
    let view = super.makeView(withIdentifier: identifier, owner: owner)

    if identifier == NSOutlineView.disclosureButtonIdentifier {
      if let btnView = view as? NSButton {
        btnView.image = NSImage(named: "RightArrow")
        btnView.alternateImage = NSImage(named: "DownArrow")

        // can set properties of the image like the size
        btnView.image?.size = NSSize(width: 15.0, height: 15.0)
        btnView.alternateImage?.size = NSSize(width: 15.0, height: 15.0)
      }
    }
    return view
  }

}

Looks quite nice!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!