xcode cocoa nscollectionview

xcode - ¿Cómo crear NSCollectionView programáticamente desde cero?



cocoa (3)

@Bavarious Hiciste un excelente trabajo allí. Este fue solo un tutorial increíble que a veces echo de menos en los Apple Docs.

Reescribí el código de Bavarious en Swift (v2) para cualquiera que esté interesado:

// 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) } }

NSCollectionView sigue siendo una de las partes más misteriosas de Cocoa API que he visto. La documentación es deficiente y hay muchas partes móviles, muchas de las cuales a menudo se implementan en Interface Builder, lo que hace que la documentación sea un desafío.

Proporcione un código de muestra para crear el caso más simple de NSCollectionView que muestre Campos de texto o Botones sin usar Xcode, donde cada Campo de texto o Botón tiene un Título diferente. Asuma un nuevo proyecto Xcode con la window predeterminada IBOutlet.

Para este ejemplo, no se requiere ningún enlace para actualizar NSCollectionView a medida que cambia la fuente de datos. Simplemente visualice una cuadrícula de objetos prototipo y establezca el Título de cada objeto con algún valor.

Si podemos obtener un buen ejemplo de cómo hacer esto disponible para muchas personas, creo que ayudará a todos los que trabajan con NSCollectionViews y está tan desconcertado como yo.

Resumen de la solicitud

  • Proporcione código de muestra para representar NSCollectionView en un nuevo proyecto de Xcode
  • No use Interface Builder, use la ventana predeterminada IBOutlet proporcionada
  • NSCollectionView debe contener campos de texto o botones, su elección
  • Cada elemento en la vista debe tener un título diferente
  • No se requiere enlace

Si hay un código de muestra que cumple estos requisitos, proporcione un enlace, ¡sería genial!


No estoy seguro de que haya mucha información para crear una vista de colección mediante programación y sin enlaces, pero aquí va.

Introducción

Hay esencialmente cuatro componentes cuando se usa una vista de colección:

  • Vista: una subclase de NSView , responsable de mostrar la información;
  • La vista de la colección en sí misma;
  • Controlador de vista: una subclase de NSCollectionViewItem que sirve como prototipo de elemento de vista de colección;
  • Modelo: una matriz de objetos.

Por lo general, una vista está diseñada en Interface Builder, y un modelo está mediado por enlaces Cocoa.

Haciéndolo programáticamente:

Constantes

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

Ver

Esta es una vista estándar (una vista personalizada en el lenguaje de Interface Builder) que contiene un botón. Tenga en cuenta que la vista tiene un tamaño fijo.

@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

Ver controlador (Prototipo)

Normalmente, un controlador de vista carga su vista desde un archivo de punta. En los casos excepcionales en que el controlador de vista no obtiene su vista desde un archivo de punta, el desarrollador debe enviarlo -setView: before -view es recibido por el controlador de vista o sobrescribir -loadView . El siguiente código hace esto último.

Los controladores de vista reciben el objeto de modelo correspondiente a través de -setRepresentedObject: Lo he reemplazado para actualizar el título del botón cada vez que cambia el objeto del modelo. Tenga en cuenta que esto se puede lograr mediante el uso de enlaces Cocoa sin ningún código en absoluto.

Tenga en cuenta que ninguno de este código es específico para las vistas de colección; es un comportamiento de controlador de vista general.

@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

Modelo

Una simple serie de cadenas que representan títulos de botones:

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

Vista de colección

Hasta ahora, la única relación que se ha establecido es la vista ( BVView ) utilizada por el prototipo del artículo ( BVPrototype ). La vista de la colección debe ser informada del prototipo que debería estar utilizando así como del modelo del que se obtienen los datos.

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

Código fuente completo para el delegado de la aplicación

#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


Para responder la pregunta de brigadir sobre cómo enlazar a una matriz mutable.

zero''th - make titles un NSMutableArray

primero, vincula la matriz a tus elementos

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

En segundo lugar, al modificar los títulos, asegúrese de modificar el proxy.

p.ej

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