objective-c cocoa interface-builder nstableview nscell

objective c - ¿Es posible diseñar subclases NSCell en Interface Builder?



objective-c cocoa (10)

Estoy tratando de subclase NSCell para su uso en un NSTableView. La celda que quiero crear es bastante complicada, por lo que sería muy útil si pudiera diseñarla en Interface Builder y luego cargar NSCell desde una punta.

es posible? ¿Cómo lo hago?


Agregue su UITableViewCell a su tableviewcontroller y declare una propiedad IBOutlet :

@interface KuguTableViewController : UITableViewController { IBOutlet UITableViewCell *customTypeCell; } @property (readonly) UITableViewCell *customTypeCell;

... luego, en cellForRowAtIndexPath puede usar su celda y configurarla para su reutilización:

static NSString *CellIdentifier = @"CustomCell" cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) cell = customTypeCell; cell.reuseIdentifier = CellIdentifier;


Como dice Ken, NSCells y NSViews son diferentes, y usted solo puede NSView jerarquías NSView en NIB, no NSCells (que no tienen ninguna jerarquía explícita).

Por otro lado, no hay nada que le impida tener una jerarquía de NSViews y usar eso para dibujar su NSCell : podría agregarlos como una subvista de la vista principal de su celda, decirles que los visualicen y eliminarlos de la ventana y nadie Sería el más sabio

En este caso, usar un NIB funcionaría, aunque parece una tonelada de molestia. Normalmente, acabo de reemplazar el objeto que lleva NSCells por uno personalizado que toma mis NSViews , pero eso significa escribir tu propio código de manejo del mouse, que es muy delicado.

Por otro lado, mi enfoque te permite vincular los valores de las vistas en NIB, por lo que no tienes que hacer ningún trabajo adicional, lo cual es genial.


En IB, inicie un XIB vacío. Ahora vaya a la paleta y arrastre en una UITableViewCell, haga doble clic para abrir y editar.

incluya únicamente la UITableViewCell personalizada (ninguna otra UIViews u otros controles de nivel superior) - asegúrese de que sea una UITableViewCell real en IB, o no puede establecer un identificador de reutilización (en lugar de convertir una UIView en IB como su clase UITableViewCell personalizada). Luego puede agregar etiquetas o lo que quiera dentro de la celda, así como establecer el identificador de reutilización o establecer el indicador de divulgación que desee.

Para usar, proporcione un código como este en el método tableView: cellForRow: atIndexPath:

YourCustomCellClass *cell = (YourCustomCellClass *)[tableView dequeueReusableCellWithIdentifier:<IDYouSetInXIBFile>]; if ( cell == nil ) { NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:<YourXIBName> owner:self options:nil]; id firstObject = [topLevelObjects objectAtIndex:0]; if ( [ firstObject isKindOfClass:[UITableViewCell class]] ) cell = firstObject; else cell = [topLevelObjects objectAtIndex:1]; }

Si tiene etiquetas u otros controles a los que desea hacer referencia en su código, conéctelos en IB a su clase de celda personalizada, NO al propietario del archivo, que no necesita establecer con el código anterior (puede dejarlo como NSObject). )

Editar: Noto que realmente está buscando una respuesta NSCell, pero el enfoque del código para usar IB debe ser idéntico en Cocoa con el código Cocoa Touch que utilicé arriba ya que loadNibNamed es una llamada Cocoa estándar.


La pregunta era sobre una subclase de NSCell; las otras respuestas parecen estar haciendo otra cosa, probablemente aprovechando que UITableViewCell sea una vista.

NSCell no es una vista. Si bien establecer una celda personalizada en IB sería una cosa útil para poder hacer, creo que la respuesta es básicamente "no, esto no es posible". Cuando subclasifica NSCell, simplemente está haciendo su propio dibujo. No hay subcélulas de soporte ni configuración automática parametrizada (en los resortes y puntales NSView), que sospecho que es lo que está buscando.

La única advertencia es que podría diseñar una subclase NSCell que hiciera el diseño de los subelementos y los parámetros proporcionados para establecer esos subelementos y todos los parámetros ajustables. Luego, necesitaría escribir un complemento de IB para que esa celda y el inspector de acompañamiento estén disponibles en IB en el momento del diseño.

Esto, sin embargo, es probablemente más difícil que escribir una pequeña aplicación personalizada que hace más o menos lo mismo. Ponga un NSCell en un control en el medio de una ventana y conviértase en UI para ajustar los parámetros que le interesan. Los enlaces pueden hacer esto bastante sencillo para posicionar cosas (es decir, vincular un valor x a un control deslizante), aunque lo hará no obtener la manipulación directa de los elementos, por supuesto. Cuando hayas terminado, puedes archivar tu celda y cargar el archivo en tiempo de ejecución en tu aplicación real, o simplemente puedes desconectar las propiedades y configurarlas en el código de tu aplicación.


Lo hago así:

/* example of a silly way to load a UITableViewCell from a standalone nib */ + (CEntryTableViewCell *)cell { // TODO -- this is really silly. NSArray *theObjects = [[NSBundle mainBundle] loadNibNamed:@"EntryTableViewCell" owner:self options:NULL]; for (id theObject in theObjects) if ([theObject isKindOfClass:self]) return(theObject); NSAssert(NO, @"Could not find object of class CEntryTableViewCell in nib"); return(NULL); }

Sin embargo, no es muy eficiente y si está cargando muchos datos, puede perjudicarlo. Por supuesto, debería usar un reuseIdentifier que debería obligar a este código a ejecutarse solo unas pocas veces por tabla.


Joar Wingfors escribió un artículo para Stepwise hace algunos años sobre un tema relacionado, Subvistas en TableView Rows .

La técnica principal es crear un NSCell que pueda alojar un NSView. Si fuera a hacer esto, podría diseñar una subclase NSView en el Interface Builder que podría incrustar en cualquier lugar donde necesite esa celda específica.

Otra posibilidad, si puede apuntar a Leopard, es ver si necesita usar un NSTableView o si puede usar un NSCollectionView. Las vistas de colección tratan directamente en términos de "vistas de elementos" en lugar de en celdas, por lo que son mucho más sencillas de diseñar en Interface Builder.


Algunas respuestas en este hilo han salido del tema porque están hablando de Cocoa Touch, cuando la pregunta original era sobre Cocoa: las 2 API son bastante diferentes en este aspecto y Cocoa Touch lo hace fácil porque UITableViewCell es una subclase de vista. NSCell no lo es, y ese es el problema

Para obtener información, tuve que hacer algo muy similar en NSOutlineView recientemente, que es básicamente lo mismo, pero un poco más difícil si se tiene en cuenta porque tiene que lidiar con la divulgación / colapso de los niveles. Si está interesado en el código, lo publiqué aquí: http://www.stevestreeting.com/2010/08/08/cocoa-tip-using-custom-table-outline-cells-designed-in-ib /

HTH


1) Crear NSViewController TableViewCell.h

2) Crear en TableViewCell.h algunos procedimientos como

-(void)setText:(NSString *)text image:(NSImage *)image

3) En la clase principal #import "TableViewCell.h"

4) En clase principal en -(NSView *)tableView:viewForTableColumn:row: write:

NSImage *img = //some image TableViewCell *cell = [[TableViewCell alloc] initWithWindowNibName:@"TableViewCell"]; cell.view.init; [cell setText:@"some text" image:img]; return cell;

Espero que esto ayude =)


Quiero brindar un enfoque más moderno aquí.

Comenzando con iOS 5, UITableView tiene un método

(void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier

Una vez que haya registrado su NIB que contiene su celda, solo use

- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier

para obtener una nueva célula Si una celda está disponible para su reutilización, se devolverá; de lo contrario, se creará automáticamente una nueva celda, y en ese caso esto significa que se cargará desde el archivo NIB.


Sin embargo, encontré algunos ejemplos interesantes que no entiendo del todo.

Los últimos 2 ejemplos funcionan con NSTableViewDataSource y NSTableViewDelegate . Me gustaría usar Bindings y ArrayController en InterfaceBuilder para conectar otros elementos de la interfaz de usuario como campos de texto.