16

我正在尝试在基于视图的 NSOutlineView 中自定义披露箭头的外观。我看到建议使用

- (void)outlineView:(NSOutlineView *)outlineView willDisplayOutlineCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item

委托方法来实现它。问题是由于某种原因没有调用此方法。我有 2 个自定义单元格视图 - 一个用于项目,第二个用于标题项目。可能是基于视图的大纲视图不调用此方法吗?可能是狮子坏了?

请阐明一些观点。

4

4 回答 4

32

解决方案1:

子类 NSOutlineView 并覆盖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;
}

对于源列表,请使用NSOutlineViewShowHideButtonKey.

解决方案2:

界面生成器

按钮被添加到列中并且标识符设置为NSOutlineViewDisclosureButtonKey

在此处输入图像描述

官方文档来自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"
于 2013-12-08T14:17:47.987 回答
11

此答案是在考虑 OS X 10.7 的情况下编写的,对于较新版本的 OS X/macOS,请参阅WetFish 的答案

该方法不会被调用,因为它仅与基于单元格的大纲视图相关。

在基于视图的大纲视图中,显示三角形是可展开行的行视图中的常规按钮。我不知道它是在哪里添加的,但确实如此,并且NSView'sdidAddSubview:方法恰好处理了视图被添加到其他地方的情况。

因此, subclassNSTableRowView和 override didAddSubview:,如下所示:

-(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"]];
    }
}

当然,您的大纲视图的委托必须实现outlineView:rowViewForItem:以返回新的行视图。

尽管名称,frameOfOutlineCellAtRow:ofNSOutlineView仍然被称为基于视图的轮廓视图,因此对于三角形的定位,您可能希望子类化轮廓视图并覆盖该方法。

于 2012-06-21T08:23:29.203 回答
8

对于 Swift 4.2 macOS 10.14,@WetFish 的回答可以实现如下:

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
  }

}

看起来相当不错!

于 2018-07-01T07:42:54.397 回答
2

@Monolo 的答案的 Swift2 版本:

override func didAddSubview(subview: NSView) {
    super.didAddSubview(subview)
    if let sv = subview as? NSButton {
        sv.image = NSImage(named:"icnArwRight")
        sv.alternateImage = NSImage(named:"icnArwDown")
    }
}
于 2016-09-05T12:52:21.047 回答