NSCollectionView
は、これまでに見たCocoa APIの最も神秘的な部分の1つです。ドキュメントは不十分であり、多くの可動部分があり、その多くはInterface Builderで実装されることが多いため、ドキュメント作成は困難です。
Xcodeを使用せずにテキストフィールドまたはボタンのいずれかを表示するNSCollectionView
の最も単純なケースを作成するためのサンプルコードを提供してください。各テキストフィールドまたはボタンには異なるタイトルがあります。デフォルトのwindow
IBOutletを持つ新しいXcodeプロジェクトを想定します。
この例では、データソースが変更されたときにNSCollectionViewを更新するためのバインディングは必要ありません。プロトタイプオブジェクトのグリッドを表示し、各オブジェクトのタイトルをある値に設定するだけです。
これを行う方法の良い例を多くの人が利用できるようになれば、NSCollectionViews
を使用していて私と同じように困惑しているすべての人に役立つと思います。
リクエストの概要
これらの要件を満たすサンプルコードがある場合は、リンクを提供してください。
プログラムでバインディングを使用せずにコレクションビューを作成することで多くの洞察が得られるかどうかはわかりませんが、ここにあります。
コレクションビューを使用する場合、基本的に4つのコンポーネントがあります。
NSView
のサブクラス。NSCollectionViewItem
のサブクラス。通常、ビューはInterface Builderで設計され、モデルはCocoaバインディングによって仲介されます。
プログラムでそれを行う:
static const NSSize buttonSize = {80, 20};
static const NSSize itemSize = {100, 40};
static const NSPoint buttonOrigin = {10, 10};
これは、ボタンを含む標準ビュー(Interface Builder用語でのカスタムビュー)です。ビューのサイズは固定されていることに注意してください。
@interface BVView : NSView
@property (weak) NSButton *button;
@end
@implementation BVView
@synthesize button;
- (id)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:(NSRect){frameRect.Origin, itemSize}];
if (self) {
NSButton *newButton = [[NSButton alloc]
initWithFrame:(NSRect){buttonOrigin, buttonSize}];
[self addSubview:newButton];
self.button = newButton;
}
return self;
}
@end
通常、ビューコントローラーはnibファイルからビューを読み込みます。ビューコントローラーがnibファイルからビューを取得しないまれなケースでは、開発者は-setView:
がビューコントローラーによって受信される前に-view
を送信するか、または-loadView
をオーバーライドする必要があります。 。次のコードは後者を実行します。
ビューコントローラは、-setRepresentedObject:
を介して対応するモデルオブジェクトを受け取ります。モデルオブジェクトが変更されるたびにボタンのタイトルを更新するようにオーバーライドしました。これは、コードなしでCocoaバインディングを使用することによって実現できることに注意してください。
このコードはコレクションビューに固有のものではないことに注意してください。これは一般的なビューコントローラーの動作です。
@interface BVPrototype : NSCollectionViewItem
@end
@implementation BVPrototype
- (void)loadView {
[self setView:[[BVView alloc] initWithFrame:NSZeroRect]];
}
- (void)setRepresentedObject:(id)representedObject {
[super setRepresentedObject:representedObject];
[[(BVView *)[self view] button] setTitle:representedObject];
}
@end
ボタンのタイトルを表す文字列の単純な配列:
@property (strong) NSArray *titles;
self.titles = [NSArray arrayWithObjects:@"Case", @"Molly", @"Armitage",
@"Hideo", @"The Finn", @"Maelcum", @"Wintermute", @"Neuromancer", nil];
これまでに確立された唯一の関係は、アイテムのプロトタイプ(BVView
)によって使用されるビュー(BVPrototype
)です。コレクションビューには、使用するプロトタイプと、データを取得するモデルを通知する必要があります。
NSCollectionView *cv = [[NSCollectionView alloc]
initWithFrame:[[[self window] contentView] frame]];
[cv setItemPrototype:[BVPrototype new]];
[cv setContent:[self titles]];
#import "BVAppDelegate.h"
static const NSSize buttonSize = { 80, 20 };
static const NSSize itemSize = { 100, 40 };
static const NSPoint buttonOrigin = { 10, 10 };
@interface BVView : NSView
@property (weak) NSButton *button;
@end
@implementation BVView
@synthesize button;
- (id)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:(NSRect){frameRect.Origin, itemSize}];
if (self) {
NSButton *newButton = [[NSButton alloc]
initWithFrame:(NSRect){buttonOrigin, buttonSize}];
[self addSubview:newButton];
self.button = newButton;
}
return self;
}
@end
@interface BVPrototype : NSCollectionViewItem
@end
@implementation BVPrototype
- (void)loadView {
[self setView:[[BVView alloc] initWithFrame:NSZeroRect]];
}
- (void)setRepresentedObject:(id)representedObject {
[super setRepresentedObject:representedObject];
[[(BVView *)[self view] button] setTitle:representedObject];
}
@end
@interface BVAppDelegate ()
@property (strong) NSArray *titles;
@end
@implementation BVAppDelegate
@synthesize window = _window;
@synthesize titles;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.titles = [NSArray arrayWithObjects:@"Case", @"Molly", @"Armitage",
@"Hideo", @"The Finn", @"Maelcum", @"Wintermute", @"Neuromancer", nil];
NSCollectionView *cv = [[NSCollectionView alloc]
initWithFrame:[[[self window] contentView] frame]];
[cv setItemPrototype:[BVPrototype new]];
[cv setContent:[self titles]];
[cv setAutoresizingMask:(NSViewMinXMargin
| NSViewWidthSizable
| NSViewMaxXMargin
| NSViewMinYMargin
| NSViewHeightSizable
| NSViewMaxYMargin)];
[[[self window] contentView] addSubview:cv];
}
@end
@ババリアスあなたはそこで素晴らしい仕事をしました。これは、Apple Docs。
Swift(v2))でBavariousのコードを書き直しました。
// AppDelegate.Swift:
import Cocoa
let buttonSize:NSSize = NSSize(width: 80, height: 20)
let itemSize:NSSize = NSSize(width: 100, height: 40)
let buttonOrigin:NSPoint = NSPoint(x: 10, y: 10)
let titles:[String] = ["Case", "Molly", "Armitage", "Hideo", "The Finn", "Maelcum", "Wintermute", "Neuromancer"]
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
func applicationDidFinishLaunching(aNotification: NSNotification) {
let cv = NSCollectionView(frame: self.window.contentView!.frame)
cv.itemPrototype = BVTemplate()
cv.content = titles
cv.autoresizingMask = NSAutoresizingMaskOptions.ViewMinXMargin
.union(NSAutoresizingMaskOptions.ViewWidthSizable)
.union(NSAutoresizingMaskOptions.ViewMaxXMargin)
.union(NSAutoresizingMaskOptions.ViewMinYMargin)
.union(NSAutoresizingMaskOptions.ViewMaxYMargin)
.union(NSAutoresizingMaskOptions.ViewHeightSizable)
window.contentView!.addSubview(cv)
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
// BVTemplate.Swift:
import Cocoa
class BVTemplate: NSCollectionViewItem {
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
override func loadView() {
print("loadingView")
self.view = BVView(frame: NSZeroRect)
}
override var representedObject:AnyObject? {
didSet {
if let representedString = representedObject as? String {
(self.view as! BVView).button?.title = representedString
}
}
}
}
// BVView.Swift:
import Cocoa
class BVView: NSView {
var button:NSButton?
override init(frame frameRect: NSRect) {
super.init(frame: NSRect(Origin: frameRect.Origin, size: itemSize))
let newButton:NSButton = NSButton(frame: NSRect(Origin: buttonOrigin, size: buttonSize))
self.addSubview(newButton)
self.button = newButton
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
可変配列にバインドする方法に関するbrigadirの質問に答えます。
0番目-タイトルをNSMutableArray
にする
最初に-配列をアイテムにバインドします
[cv bind:NSContentBinding
toObject:self
withKeyPath:@"titles"
options:NULL];
2番目-タイトルを変更するときは、必ずプロキシを変更してください。
例えば.
NSMutableArray *kvcTitles = [self mutableArrayValueForKey:@"titles"];
[kvcTitles removeLastObject];