32

我有NSCollectionView一个次要但关键的例外情况。获取并突出显示集合中的选定项目。

在 Snow Leopard 之前,我已经完成了所有这些工作,但似乎发生了一些变化,我无法完全确定它,所以我NSCollectionView回到了基本测试,并按照 Apple 的文档在此处创建 NSCollectionView:

http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/CollectionViews/Introduction/Introduction.html

按照快速入门指南,集合视图可以正常工作。但是,本指南不讨论除"There are such features as incorporating image views, setting objects as selectable or not selectable and changing colors if they are selected".

以此为例,我进入下一步,NSCollectionView使用控制器键将 Array Controller 绑定到selectionIndexes,认为这将绑定我在NSCollectionView和 数组控制器之间所做的任何选择,从而触发 KVO 通知。我还将NSCollectionViewIB 设置为可选。

似乎没有选择委托,NSCollectionView并且与大多数 Cocoa UI 视图不同,似乎没有默认选择的突出显示。

所以我的问题真的归结为一个相关的问题,但是两个不同的问题。

  1. 如何捕获对项目的选择?
  2. 如何显示项目的亮点?

NSCollectionView的编程指南似乎少之又少,大多数通过 Google 进行的搜索似乎都提取了 Snow Leopard 之前的实现,或者在单独的 XIB 文件中使用视图。

对于后者(视图的单独 XIB 文件),我不明白为什么这应该是先决条件,否则我会怀疑 Apple 不会将视图包含在与集合视图项相同的包中。

我知道这将是一个“只见树木不见森林”的问题——所以我已经准备好迎接“doh!”。片刻。

像往常一样,非常感谢任何和所有帮助。

更新 1

好的,所以我想找到选定的项目,但还没有想出突出显示。对于对确定所选项目感兴趣的人(假设您遵循 Apple 指南):

在控制器(在我的测试用例 App Delegate 中)中,我添加了以下内容:

在 awakeFromNib

[personArrayController addObserver:self
       forKeyPath:@"selectionIndexes" 
       options:NSKeyValueObservingOptionNew
       context:nil];

新方法

-(void)observeValueForKeyPath:(NSString *)keyPath 
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void *)context
{
    if([keyPath isEqualTo:@"selectionIndexes"])
    {
        if([[personArrayController selectedObjects] count] > 0)
        {
            if ([[personArrayController selectedObjects] count] == 1)
            {
                personModel * pm = (PersonModel *) 
                       [[personArrayController selectedObjects] objectAtIndex:0];
                NSLog(@"Only 1 selected: %@", [pm name]);
            }
            else
            {
                // More than one selected - iterate if need be
            }
        }
    }

不要忘记为非 GC 解除分配

-(void)dealloc
{
    [personArrayController removeObserver:self 
                               forKeyPath:@"selectionIndexes"];
    [super dealloc];
}

仍在寻找高光分辨率...

更新 2

接受了 Macatomy 的建议,但仍有问题。发布相关的类方法,看看我哪里出错了。

我的视图.h

#import <Cocoa/Cocoa.h>

@interface MyView : NSView {
    BOOL selected;
}

@property (readwrite) BOOL selected;

@end

我的视图.m

#import "MyView.h"

@implementation MyView

@synthesize selected;

-(id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code here.
    }
    return self;
}

-(void)drawRect:(NSRect)dirtyRect
{
    NSRect outerFrame = NSMakeRect(0, 0, 143, 104);
    NSRect selectedFrame = NSInsetRect(outerFrame, 2, 2);

    if (selected)
        [[NSColor yellowColor] set];
    else
        [[NSColor redColor] set];

    [NSBezierPath strokeRect:selectedFrame];
}

@end

我的CollectionViewItem.h

#import <Cocoa/Cocoa.h>
@class MyView;

@interface MyCollectionViewItem : NSCollectionViewItem {

}

@end

"MyCollectionViewItem.m*

#import "MyCollectionViewItem.h"
#import "MyView.h"

@implementation MyCollectionViewItem

-(void)setSelected:(BOOL)flag
{

    [(MyView *)[self view] setSelected:flag];
    [(MyView *)[self view] setNeedsDisplay:YES];
}

@end
4

9 回答 9

34

如果不同的背景颜色足以作为突出显示,您可以简单地使用 NSBox 作为您的集合项目视图的根项目。用您选择的突出显示颜色填充 NSBox。将 NSBox 设置为自定义,以便填充工作。将 NSBox 设置为透明。

将 NSBox 的透明度属性绑定到 File Owner(Collection Item) 的选定属性 将透明绑定的值转换器设置为 NSNegateBoolean。

我试图附上界面生成器屏幕截图,但我被拒绝了,因为我是新手:-(

于 2011-01-31T15:40:48.180 回答
26

做起来并不难。确保在 Interface Builder 中为 NSCollectionView 启用了“选择”。然后在您用于原型视图的 NSView 子类中,声明一个名为 "selected" 的属性:

@property (readwrite) BOOL selected;

此处更新代码:(添加了超级调用)

子类 NSCollectionViewItem 并覆盖 -setSelected:

- (void)setSelected:(BOOL)flag
{
    [super setSelected:flag];
    [(PrototypeView*)[self view] setSelected:flag];
    [(PrototypeView*)[self view] setNeedsDisplay:YES];
}

然后你需要在原型视图的 drawRect: 方法中添加代码来绘制高亮:

- (void)drawRect:(NSRect)dirtyRect 
{
    if (selected) {
       [[NSColor blueColor] set];
       NSRectFill([self bounds]);
    }
}

这只是在选择时将视图填充为蓝色,但可以自定义以任何您想要的方式绘制突出显示。我在自己的应用程序中使用过它,效果很好。

于 2010-03-29T23:10:56.647 回答
5

如果您没有将 NSView 子类化为原型视图,您也可以采用另一种方式。

在您的子类 NSCollectionViewItem 覆盖setSelected:

- (void)setSelected:(BOOL)selected
{
    [super setSelected:selected];
    if (selected)
        self.view.layer.backgroundColor = [NSColor redColor].CGColor;
    else
        self.view.layer.backgroundColor = [NSColor clearColor].CGColor;
}

当然,正如我之前所有聪明人所说,确保在 Interface Builder 中为 NSCollectionView 启用了“选择”。

于 2013-12-09T19:16:15.457 回答
4

在您的NSCollectionViewItem子类中,覆盖isSelected并更改图层的背景颜色。在 macOS 10.14 和 Swift 4.2 中测试

class Cell: NSCollectionViewItem {

  override func loadView() {    
    self.view = NSView()
    self.view.wantsLayer = true
  }

  override var isSelected: Bool {
    didSet {
      self.view.layer?.backgroundColor = isSelected ? NSColor.gray.cgColor : NSColor.clear.cgColor
    }
  }
}
于 2019-02-20T19:33:49.200 回答
2

由于没有一个现有的答案对我来说效果很好,所以这是我的看法。将 CollectionView 项的子类更改为 SelectableCollectionViewItem。这是它的代码。附带一个可绑定的 textColor 属性,用于将您的文本标签 textColor 绑定到挂钩。

@implementation SelectableCollectionViewItem

+ (NSSet *)keyPathsForValuesAffectingTextColor
{
    return [NSSet setWithObjects:@"selected", nil];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.wantsLayer = YES;
}

- (void) viewDidAppear
{
    // seems the inital selection state is not done by Apple in a KVO compliant manner, update background color manually
    [self updateBackgroundColorForSelectionState:self.isSelected];
}

- (void)updateBackgroundColorForSelectionState:(BOOL)flag
{
    if (flag)
    {
        self.view.layer.backgroundColor = [[NSColor alternateSelectedControlColor] CGColor];
    }
    else
    {
        self.view.layer.backgroundColor = [[NSColor clearColor] CGColor];
    }
}

- (void)setSelected:(BOOL)flag
{
    [super setSelected:flag];
    [self updateBackgroundColorForSelectionState:flag];
}

- (NSColor*) textColor
{
    return self.selected ? [NSColor whiteColor] : [NSColor textColor];
}
于 2015-03-01T21:01:06.683 回答
1

就我而言,我想要一个图像(复选标记)来指示对象的选择。将 ImageWell 拖到 Collection Item nib。设置所需的图像并将其标记为隐藏。转到绑定检查器并将隐藏属性绑定到集合视图项。

在此处输入图像描述

(在我的例子中,我为 CollectionViewItem 创建了一个单独的 nib,因此它绑定到 File 的所有者。如果不是这种情况,并且 Item 视图与 CollectionView 在同一个 nib 中,则绑定到 Collection View Item)

将模型键路径设置为selected并将值转换器设置为NSNegateBoolean。现在就是这样,只要选择了单个单元格/项目,图像就会可见,从而指示选择。

添加到Alter的答案。

将 NSBox 设置为根项。只需创建一个新的 IB 文档(比如 CollectionItem)并将一个 NSBox 拖到空白区域。现在根据需要在框中添加所有元素。现在单击文件的所有者并将自定义类设置为NSCollectionViewItem.

在此处输入图像描述

并在NSCollectionView添加的笔尖中更改笔尖名称CollectionViewItem

在此处输入图像描述

在 NSBox 中,将剩余元素绑定到Files Owner. 对于标签,它类似于:

在此处输入图像描述

现在要获得Alter在他的回答中提到的突出显示颜色,请在“填充颜色”选项中设置所需的颜色组合,将其设置NSBox为透明并绑定透明度属性,如下所示:

在此处输入图像描述

现在,选择收集视图项目时,您应该能够看到框的填充颜色。

于 2014-05-13T09:00:12.353 回答
0

这太棒了,非常感谢!我正在为此苦苦挣扎!

向其他人澄清:

 [(PrototypeView*)[self view] setSelected:flag];
 [(PrototypeView*)[self view] setNeedsDisplay:YES];

将 PrototypeView* 替换为您的原型类名称。

于 2011-02-02T20:02:00.093 回答
0

如果您正在寻找更新的 Swift 解决方案,请参阅此回复

class MyViewItem: NSCollectionViewItem {
  override var isSelected: Bool {
      didSet {
        self.view.layer?.backgroundColor = (isSelected ? NSColor.blue.cgColor : NSColor.clear.cgColor)
      }
  }
  etc...
}
于 2018-10-15T15:35:19.883 回答
0

这是带有选择的完整 Swift NSCollectionViewItem。不要忘记将 NSCollectioView 设置为在 IB 中或以编程方式可选择。在 macOS Mojave (10.14) 和 High Sierra (10.13.6) 下测试。

import Cocoa

class CollectionViewItem: NSCollectionViewItem {

private var selectionColor : CGColor {
    let selectionColor : NSColor = (isSelected ? .alternateSelectedControlColor : .clear)
    return selectionColor.cgColor
}

override var isSelected: Bool {
    didSet {
        super.isSelected = isSelected
        updateSelection()
        // Do other stuff if needed
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    view.wantsLayer = true
    updateSelection()
}

override func prepareForReuse() {
    super.prepareForReuse()
    updateSelection()
}

private func updateSelection() {
    view.layer?.backgroundColor = self.selectionColor
}
}
于 2019-01-31T13:55:52.137 回答