web-dev-qa-db-ja.com

NSCollectionViewでの選択のハイライト

動作中のNSCollectionViewがありますが、マイナーですが重要な例外が1つあります。コレクション内の選択したアイテムを取得して強調表示します。

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にバインドする次のステップに進みました。これにより、NSCollectionViewとアレイコントローラー、したがってKVO通知を起動します。また、NSCollectionViewをIBで選択できるように設定しました。

NSCollectionViewの選択デリゲートがないようで、ほとんどのCocoa UIビューとは異なり、デフォルトで選択されているハイライトがないようです。

したがって、私の問題は実際には関連する問題に帰着しますが、2つの明確な質問があります。

  1. アイテムの選択をキャプチャするにはどうすればよいですか?
  2. アイテムのハイライトを表示するにはどうすればよいですか?

NSCollectionViewのプログラミングガイドはほとんどないようで、Googleを介したほとんどの検索は、Snow Leopard以前の実装をプルアップするか、別のXIBファイルでビューを使用するようです。

後者(ビュー用の個別のXIBファイル)の場合、これが前提条件である理由がわかりません。そうでない場合、Appleはビューを同じに含めなかったと思われます。コレクションビューアイテムとしてバンドルします。

これは「木々の木が見えない」問題になることはわかっているので、「doh!」の準備ができています。瞬間。

いつものように、ありとあらゆるものが大いに感謝されます。

更新1

OK、それで私は選択されたアイテムを見つけることを考えました、しかしハイライトをまだ理解していません。選択したアイテムを理解することに興味がある場合(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のdeallocを忘れないでください

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

まだハイライトの解像度を探しています...

アップデート2

Macatomyのアドバイスを受けましたが、それでも問題がありました。関連するクラスメソッドを投稿して、どこが間違っているかを確認します。

MyView.h

#import <Cocoa/Cocoa.h>

@interface MyView : NSView {
    BOOL selected;
}

@property (readwrite) BOOL selected;

@end

MyView.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

MyCollectionViewItem.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
32
Hooligancat

それほど難しいことではありません。 InterfaceBuilderの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]);
    }
}

これは、選択時にビューを青で塗りつぶすだけですが、ハイライトを任意の方法で描画するようにカスタマイズできます。私はこれを自分のアプリで使用しましたが、うまく機能します。

25
indragie

別の背景色でハイライトとして十分な場合は、コレクションアイテムビューのルートアイテムとしてNSBoxを使用できます。 NSBoxに選択したハイライトカラーを入力します。塗りつぶしが機能するように、NSBoxをカスタムに設定します。 NSBoxを透過に設定します。

NSBoxのtransparent属性をFileOwner(Collection Item)の選択された属性にバインドします。透過バインドの値トランスフォーマーをNSNegateBooleanに設定します。

Interface Builderのスクリーンショットを添付しようとしましたが、拒否されましたbcos私は初心者です:-(

33
Alternegro

プロトタイプビューの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;
}

そしてもちろん、私の前のすべての賢明な人々が言っ​​たように、InterfaceBuilderのNSCollectionViewで「選択」が有効になっていることを確認してください。

3
Gasper Kolenc

既存の答えはどれも私にとってうまく機能しなかったので、ここに私の見解があります。 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];
}
2
iljawascoding

私の場合、オブジェクトの選択を示す画像(チェックマーク)が必要でした。 ImageWellをコレクションアイテムのペン先にドラッグします。目的の画像を設定し、非表示としてマークします。バインディングインスペクターに移動し、非表示の属性をコレクションビューアイテムにバインドします。

enter image description here

(私の場合、CollectionViewItem用に別のペン先を作成したので、ファイルの所有者にバインドされました。そうでなく、アイテムビューがCollectionViewと同じペン先にある場合は、コレクションビューアイテムにバインドします) ==

モデルのキーパスをselectedに設定し、値トランスフォーマーをNSNegateBooleanに設定します。これで、個々のセル/アイテムが選択されるたびに画像が表示され、選択が示されます。

アルターの答えに追加します。

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

これで、コレクションビューアイテムを選択すると、ボックスの塗りつぶしの色が表示されるはずです。

1
GoodSp33d

NSCollectionViewItemサブクラスで、isSelectedをオーバーライドし、レイヤーの背景色を変更します。 macOS10.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
    }
  }
}
1
onmyway133

これは素晴らしかった、どうもありがとう!私はこれに苦労していました!

他の人に明確にするために:

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

PrototypeView *をプロトタイプクラス名の名前に置き換えます。

0
Rasmus Styrk

更新されたSwiftソリューション、 この応答を参照 を探している場合。

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

これが完全なSwift NSCollectionViewItemと選択です。NSCollectioViewをIBまたはプログラムで選択可能に設定することを忘れないでください。macOSMojave(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
}
}
0
Darkwonder