動作中のNSCollectionView
がありますが、マイナーですが重要な例外が1つあります。コレクション内の選択したアイテムを取得して強調表示します。
Snow Leopardの前はこれらすべての作業を行っていましたが、何かが変わったようで、指を置くことができないため、NSCollectionView
を基本テストに戻し、Appleのドキュメントに従いました。ここでNSCollectionViewを作成する場合:
コレクションビューは、クイックスタートガイドに従って正常に機能します。ただし、このガイドでは、"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つの明確な質問があります。
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
それほど難しいことではありません。 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]);
}
}
これは、選択時にビューを青で塗りつぶすだけですが、ハイライトを任意の方法で描画するようにカスタマイズできます。私はこれを自分のアプリで使用しましたが、うまく機能します。
別の背景色でハイライトとして十分な場合は、コレクションアイテムビューのルートアイテムとしてNSBoxを使用できます。 NSBoxに選択したハイライトカラーを入力します。塗りつぶしが機能するように、NSBoxをカスタムに設定します。 NSBoxを透過に設定します。
NSBoxのtransparent属性をFileOwner(Collection Item)の選択された属性にバインドします。透過バインドの値トランスフォーマーをNSNegateBooleanに設定します。
Interface Builderのスクリーンショットを添付しようとしましたが、拒否されましたbcos私は初心者です:-(
プロトタイプビューの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で「選択」が有効になっていることを確認してください。
既存の答えはどれも私にとってうまく機能しなかったので、ここに私の見解があります。 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];
}
私の場合、オブジェクトの選択を示す画像(チェックマーク)が必要でした。 ImageWellをコレクションアイテムのペン先にドラッグします。目的の画像を設定し、非表示としてマークします。バインディングインスペクターに移動し、非表示の属性をコレクションビューアイテムにバインドします。
(私の場合、CollectionViewItem用に別のペン先を作成したので、ファイルの所有者にバインドされました。そうでなく、アイテムビューがCollectionViewと同じペン先にある場合は、コレクションビューアイテムにバインドします) ==
モデルのキーパスをselected
に設定し、値トランスフォーマーをNSNegateBoolean
に設定します。これで、個々のセル/アイテムが選択されるたびに画像が表示され、選択が示されます。
アルターの答えに追加します。
NSBoxをルートアイテムとして設定します。新しいIBドキュメント(CollectionItemなど)を作成し、NSBoxを空の領域にドラッグするだけです。次に、必要に応じてボックス内にすべての要素を追加します。次に、[ファイルの所有者]をクリックして、カスタムクラスをNSCollectionViewItem
に設定します。
また、NSCollectionView
が追加されているペン先で、CollectionViewItem
のペン先名を変更します。
NSBoxで、残りの要素をFiles Owner
にバインドします。ラベルの場合、次のようになります。
ここで、ハイライトの色を彼の回答で言及されているAlterとして取得するには、[塗りつぶしの色]オプションで目的の色の組み合わせを設定し、NSBox
を透明に設定し、以下のように透明属性をバインドします。
これで、コレクションビューアイテムを選択すると、ボックスの塗りつぶしの色が表示されるはずです。
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
}
}
}
これは素晴らしかった、どうもありがとう!私はこれに苦労していました!
他の人に明確にするために:
[(PrototypeView*)[self view] setSelected:flag];
[(PrototypeView*)[self view] setNeedsDisplay:YES];
PrototypeView *をプロトタイプクラス名の名前に置き換えます。
更新されたSwiftソリューション、 この応答を参照 を探している場合。
class MyViewItem: NSCollectionViewItem {
override var isSelected: Bool {
didSet {
self.view.layer?.backgroundColor = (isSelected ? NSColor.blue.cgColor : NSColor.clear.cgColor)
}
}
etc...
}
これが完全な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
}
}