选择在NSCollectionView中突出显示

时间:2010-03-29 21:59:52

标签: objective-c cocoa nsview nscollectionview nscollectionviewitem

我有一个工作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将阵列控制器绑定到selectionIndexes,认为这将绑定{{1}之间的任何选择和数组控制器,从而触发KVO通知。我还将NSCollectionView设置为可在IB中选择。

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

所以我的问题实际上归结为一个相关问题,但有两个截然不同的问题。

  1. 如何捕捉项目的选择?
  2. 如何显示项目的突出显示?
  3. NSCollectionView的编程指南似乎很少,而且大多数通过Google搜索似乎都会提升Snow Leopard之前的实现,或者在单独的XIB文件中使用该视图。

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

    我知道这将是一个“看不见木头为树”的问题 - 所以我已经准备好了“doh!”时刻。

    像往常一样,任何人都非常感激。

    更新1

    好的,所以我想找到所选的项目,但尚未确定突出显示。有兴趣计算所选项目(假设您正在关注Apple指南):

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

    在awakeFromNib

    NSCollectionView

    新方法

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

    不要忘记为非GC发送dealloc

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

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

    更新2

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

    MyView.h

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

    MyView.m

    #import <Cocoa/Cocoa.h>
    
    @interface MyView : NSView {
        BOOL selected;
    }
    
    @property (readwrite) BOOL selected;
    
    @end
    

    MyCollectionViewItem.h

    #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
    

    “MyCollectionViewItem.m *

    #import <Cocoa/Cocoa.h>
    @class MyView;
    
    @interface MyCollectionViewItem : NSCollectionViewItem {
    
    }
    
    @end
    

9 个答案:

答案 0 :(得分:33)

如果不同的背景颜色足以作为突出显示,您可以简单地使用NSBox作为集合项视图的根项。 使用您选择的高亮颜色填充NSBox。 将NSBox设置为Custom,这样填充就可以了。 将NSBox设置为透明。

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

我试图附加界面生成器截图,但我被拒绝了bcos我是新手: - (

答案 1 :(得分:25)

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

@property (readwrite) BOOL selected;

此处更新的代码:(添加超级电话)

子类NSCollectionViewItem和override -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]);
    }
}

只需在选中时以蓝色填充视图,但可以自定义以任意方式绘制高光。我已经在我自己的应用程序中使用了它并且效果很好。

答案 2 :(得分:3)

如果你没有为你的原型视图继承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启用了“Selection”。

答案 3 :(得分: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];
}

答案 4 :(得分:1)

在我的情况下,我想要一个图像(复选标记)来表示对象的选择。将ImageWell拖动到Collection Item nib。设置所需的图像并将其标记为隐藏。转到绑定检查器并将隐藏属性绑定到Collection View Item。

enter image description here

(在我的情况下,我为CollectionViewItem创建了一个单独的nib,因此它绑定到File的所有者。如果不是这样,并且Item视图与CollectionView位于同一个nib中,则绑定到集合查看项目)

将模型关键路径设置为selected,将值转换设置为NSNegateBoolean。现在,无论何时选择单个单元格/项目,图像都将可见,因此表明选择。

添加到Alter的回答。

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

enter image description here

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

enter image description here

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

enter image description here

现在要将高亮颜色设置为答案中提到的 Alter ,在“填充颜色”选项中设置所需的颜色组合,将NSBox设置为透明并绑定透明度属性,如下所示:

enter image description here

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

答案 5 :(得分:1)

在您的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
    }
  }
}

答案 6 :(得分:0)

这太棒了,非常感谢!我正在努力解决这个问题!

向其他人澄清:

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

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

答案 7 :(得分:0)

如果您正在寻找更新的Swift解决方案see this response

class MyViewItem: NSCollectionViewItem {
  override var isSelected: Bool {
      didSet {
        self.view.layer?.backgroundColor = (isSelected ? NSColor.blue.cgColor : NSColor.clear.cgColor)
      }
  }
  etc...
}

答案 8 :(得分:0)

这是带有选择的完整Swift NSCollectionViewItem。不要忘记在IB或通过编程将NSCollectioView设置为可选。

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