2011-12-28 44 views
31

NSCollectionView vẫn là một trong những phần bí ẩn nhất của API Cocoa mà tôi từng thấy. Tài liệu kém và có nhiều bộ phận chuyển động, nhiều phần trong số đó thường được triển khai trong Trình tạo giao diện, làm cho tài liệu trở nên khó khăn.Làm thế nào để tạo NSCollectionView lập trình từ đầu?

Vui lòng cung cấp mã mẫu để tạo trường hợp đơn giản nhất là NSCollectionView hiển thị Trường văn bản hoặc Nút mà không sử dụng Xcode trong đó mỗi Trường văn bản hoặc Nút có Tiêu đề khác. Giả sử một dự án Xcode mới với mặc định là window IBOutlet.

Ví dụ này, không cần ràng buộc để cập nhật NSCollectionView khi nguồn dữ liệu thay đổi. Đơn giản chỉ cần hiển thị một lưới các đối tượng nguyên mẫu và đặt tiêu đề của từng đối tượng thành một số giá trị.

Nếu chúng ta có thể có được một ví dụ tốt về cách làm điều này có sẵn cho nhiều người, tôi nghĩ rằng nó sẽ giúp mọi người làm việc với NSCollectionViews và bị bối rối như tôi.

Tóm tắt các yêu cầu

  • Cung cấp mẫu mã để render một NSCollectionView trong một dự án Xcode mới
  • Không sử dụng giao diện Builder, làm sử dụng cửa sổ mặc định IBOutlet cung cấp
  • NSCollectionView nên chứa chữ Trường hoặc Nút, lựa chọn của bạn
  • Mỗi mục trong chế độ xem phải có một Tiêu đề khác nhau
  • Không có liên kết g là bắt buộc

Nếu có mã mẫu ở đó đáp ứng các yêu cầu này, vui lòng cung cấp liên kết, tuyệt vời!

Trả lời

59

Tôi không chắc có nhiều thông tin chi tiết trong việc tạo chế độ xem bộ sưu tập theo chương trình và không có sự ràng buộc, nhưng ở đây nó đi.

Giới thiệu

cơ bản Có bốn thành phần khi sử dụng một cái nhìn bộ sưu tập:

  • Xem: một lớp con của NSView, chịu trách nhiệm cho việc hiển thị thông tin;
  • Chế độ xem bộ sưu tập;
  • Xem bộ điều khiển: một lớp con của NSCollectionViewItem đóng vai trò là mẫu thử nghiệm xem bộ sưu tập;
  • Mô hình: một mảng các đối tượng.

Thông thường chế độ xem được thiết kế trong Trình tạo giao diện và mô hình được dàn xếp bằng các kết buộc Cocoa.

Làm nó lập trình:

Constants

static const NSSize buttonSize = {80, 20}; 
static const NSSize itemSize = {100, 40}; 
static const NSPoint buttonOrigin = {10, 10}; 

Xem

Đây là một chế độ xem chuẩn (một giao diện tùy chỉnh trong giao diện Builder cách nói) có chứa một nút. Lưu ý rằng chế độ xem có kích thước cố định.

@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 

View Controller (thử nghiệm)

Thông thường một bộ điều khiển xem tải quan điểm của mình từ một tập tin nib. Trong những trường hợp hiếm hoi mà bộ điều khiển chế độ xem không nhận được chế độ xem từ tệp nib, nhà phát triển phải gửi nó theo số -setView: trước khi -view nhận được bởi trình điều khiển chế độ xem hoặc ghi đè -loadView. Các mã sau đây không sau này.

Xem bộ điều khiển nhận đối tượng mô hình tương ứng qua -setRepresentedObject:. Tôi đã ghi đè nó để cập nhật tiêu đề nút bất cứ khi nào đối tượng mô hình thay đổi. Lưu ý rằng điều này có thể được thực hiện bằng cách sử dụng kết buộc Cocoa mà không có bất kỳ mã nào cả.

Lưu ý rằng không có mã nào cụ thể cho chế độ xem bộ sưu tập - đó là hành vi của trình điều khiển chế độ xem chung.

@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 

Mẫu

Một mảng đơn giản của chuỗi đại diện cho danh hiệu nút:

@property (strong) NSArray *titles; 
self.titles = [NSArray arrayWithObjects:@"Case", @"Molly", @"Armitage", 
    @"Hideo", @"The Finn", @"Maelcum", @"Wintermute", @"Neuromancer", nil]; 

Collection Xem

Cho đến nay, mối quan hệ duy nhất đó là được thiết lập là quan điểm (BVView) được sử dụng theo mẫu thử nghiệm (BVPrototype). Khung nhìn bộ sưu tập phải được thông báo về nguyên mẫu mà nó cần sử dụng cũng như mô hình để lấy dữ liệu từ đó.

NSCollectionView *cv = [[NSCollectionView alloc] 
    initWithFrame:[[[self window] contentView] frame]]; 
[cv setItemPrototype:[BVPrototype new]]; 
[cv setContent:[self titles]]; 

Full Source Code cho các ứng dụng Đại biểu

#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 
+15

Tài liệu trên NSCollectionView đáng ngạc nhiên kém. Bất cứ ai hiểu cách con thú thần thoại này hoạt động, và có thể chia sẻ kiến ​​thức của họ, đang giúp đỡ các nhà phát triển Objective-C ở mọi nơi. Cảm ơn nhiều. – Tronathan

+0

Bavarious, tôi có thể yêu cầu bạn hiển thị cách đồng bộ hóa chế độ xem bộ sưu tập với các mục có thể thay đổi không? – brigadir

+0

@Bavarious - cảm ơn vì đã có câu trả lời tuyệt vời. –

4

Để trả lời câu hỏi brigadir về làm thế nào để liên kết với một mảng có thể thay đổi.

zero'th - tự giới thiệu chức một NSMutableArray

đầu tiên - liên kết mảng đến các mục của bạn

[cv bind:NSContentBinding 
    toObject:self 
    withKeyPath:@"titles" 
    options:NULL]; 

Thứ hai - khi thay đổi tiêu đề, hãy chắc chắn để thay đổi proxy.

ví dụ:

NSMutableArray *kvcTitles = [self mutableArrayValueForKey:@"titles"]; 
[kvcTitles removeLastObject]; 
5

@Bavarious Bạn đã làm một công việc tuyệt vời ở đó. Đây chỉ là một hướng dẫn tuyệt vời mà đôi khi tôi bỏ lỡ ở Apple Documents.

Tôi viết lại đang Bavarious' trong Swift (v2) cho bất cứ ai quan tâm:

// 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) 
    } 
} 
Các vấn đề liên quan