NSCollectionView
仍然是我见过的Cocoa API中最神秘的部分之一。文档很差,并且有许多移动部件,其中许多通常在Interface Builder中实现,使文档具有挑战性。
请提供示例代码以创建NSCollectionView
的最简单大小写,其中显示文本字段或按钮而不使用Xcode,其中每个文本字段或按钮具有不同的标题。假设一个新的Xcode项目使用默认的window
IBOutlet。
对于此示例,在数据源更改时不需要绑定来更新NSCollectionView。只需显示原型对象的网格,并将每个对象的标题设置为某个值。
如果我们能够为很多人提供一个如何做到这一点的好例子,我认为这将有助于所有与NSCollectionViews
合作并且和我一样困惑的人。
请求摘要
如果有符合这些要求的示例代码,请提供一个链接,这很棒!
答案 0 :(得分:59)
我不确定在以编程方式创建集合视图方面有多少见解,而且没有绑定,但现在就可以了。
使用集合视图时基本上有四个组件:
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
答案 1 :(得分:5)
@Bavarious 你在那里做得很好。这只是一个很棒的教程,我有时会错过Apple Docs。
我改写了巴伐利亚' Swift(v2)中的代码适用于所有感兴趣的人:
// 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)
}
}
答案 2 :(得分:4)
回答关于如何绑定到可变数组的brigadir的问题。
零 - 将标题设为NSMutableArray
首先 - 将数组绑定到您的项目
[cv bind:NSContentBinding
toObject:self
withKeyPath:@"titles"
options:NULL];
第二 - 更改标题时,请务必修改代理。
e.g。
NSMutableArray *kvcTitles = [self mutableArrayValueForKey:@"titles"];
[kvcTitles removeLastObject];