2010-07-09 9 views
5

Básicamente, tengo un NSTableView con 1 columna, y estoy insertando cadenas largas en cada fila. Sin embargo, no todas las cadenas son largas, por lo que me gustaría que la altura de cada fila sea diferente según la longitud de la cadena.NSTableView Altura de fila basada en NSStrings

He descubierto que tengo que preguntarle a la columna qué ancho tiene, y luego preguntarle a la cuerda cuántas líneas tomará si la columna es así de ancha, y luego decidir qué tan "alta" será la NSCell ser. ¿Pero cómo hago eso? He recibido el ancho de collumn:

[[[tableView tableColumns] objectAtIndex:0] width];

pero no puedo averiguar cómo solicitar al NSString la cantidad de espacio que ocupará. O, tal vez, ¿hay una mejor manera de hacerlo?

Gracias por cualquier ayuda con anticipación.

Respuesta

10

Cree una instancia NSTextFieldCell y haga coincidir su fuente/tamaño/etc. al de la celda de datos de su columna. Pídale el -cellSizeForBounds:, pasando un rect del ancho deseado para la columna, con una gran altura (FLT_MAX?). El resultado debe ser un NSSize cuya altura puede usar.

Se vuelve más complicado si tiene más de una columna de texto de varias líneas porque tendrá que considerar todas las celdas de esa fila, tomando la más grande como la altura de su fila. Si espera muchas filas en promedio, probablemente quiera guardar en caché este trabajo, actualizarlo según sea necesario y luego simplemente hacer referencia a él cuando se invoque el método delegado de altura de fila.

+1

Por qué es necesario para crear una instancia desechable de un 'NST extFieldCell'? He podido llamar '-cellSizeForBounds:' en la misma celda sin problema? –

+0

Correcto. :-) Estaba pensando en los términos más generales de "obtener un tamaño de celda en el vacío" en lugar de usar mi cerebro y darme cuenta de que la celda existente funcionará bien. :-) –

+0

@SergeVelikanov ¿A qué te refieres? –

8

Código de acuerdo con la respuesta anterior ...

NSString *string = [[_tableViewDataSourceArray objectAtIndex:rowIndex] 
           valueForKey:@"StringToDisplay"]; 

    NSTableColumn *tableColoumn = [aTableView 
           tableColumnWithIdentifier:@"TableColumnIdentifier"]; 

    if (tableColoumn) 
    { 
    NSCell *dataCell = [tableColoumn dataCell]; 
    [dataCell setWraps:YES]; 
    [dataCell setStringValue:string]; 
    NSRect myRect = NSMakeRect(0, 0, [tableColoumn width], CGFLOAT_MAX); 
    heightOfRow = [dataCell cellSizeForBounds:myRect].height; 
    } 
3

He aquí una pequeña mejora en Robert D'Almeida's answer (I presentaron inicialmente esto como una edición, pero fue rechazado debido a que "el significado original o la intención del puesto estar perdido"). Agregué la firma del método e hice algunos otros pequeños cambios.

- (CGFloat)tableView:(NSTableView *)aTableView heightOfRow:(NSInteger)row { 
    CGFloat heightOfRow = 100; // or some other default value 

    // get the content for this table cell from the model 
    NSString *string = [[_tableViewDataSourceArray objectAtIndex:rowIndex] 
           valueForKey:@"StringToDisplay"]; 

    NSTableColumn *tableColumn = [aTableView 
           tableColumnWithIdentifier:@"TableColumnIdentifier"]; 

    if (tableColumn) { 
     NSCell *dataCell = [tableColumn dataCell]; 
     [dataCell setWraps:YES]; 
     [dataCell setStringValue:string]; 

     // See how tall it naturally would want to be if given a restricted 
     // width, but unbound height 
     NSRect myRect = NSMakeRect(0, 0, [tableColumn width], CGFLOAT_MAX); 
     heightOfRow = [dataCell cellSizeForBounds:myRect].height; 
    } 

    return heightOfRow; 
} 
1

me gusta Robert D'Almeida's answer, pero utiliza -[tableColumn dataCell], que docs de Apple dicen que "sólo es válida para las vistas de tabla basados ​​en células".

Mi intento está por debajo.

En Interface Builder (en Xcode: estoy usando 5.1.1 actualmente), configure un NSTableView.

  • la vista de tabla debería haber Modo contenido ajustado a Ver Basado
  • una de las columnas deberían tener el identificador WrapColumnIdentifier
  • que la columna debe contener un NSTableCellView, que debe contener un NSTextField (y para comprender el código siguiente, necesita saber que NSTextField contiene un NSTextFieldCell, que es una subclase de NSCell)
  • El objeto NSTextField debe tener el diseño configurado en Wraps
  • El objeto NSTextField debe tener una máscara de autosizing configurada donde las seis líneas están habilitadas (rojo fijo), de modo que cuando la tabla cambie el tamaño de la celda de la tabla, el campo de texto se redimensionará y continuará llenando la celda.

Aquí hay un método NSTableViewDelegate para usar con esa configuración. Esto hace que la altura de cada fila de la tabla se establezca de manera que la "columna de ajuste" (que contiene el NSTextField) muestre su texto sin truncamiento.

- (CGFloat)tableView:(NSTableView *)aTableView heightOfRow:(NSInteger)aRow { 
    NSTableColumn *tableColumn = [aTableView tableColumnWithIdentifier:@"WrapColumnIdentifier"]; 

    // obtain the view that would be used at this position in the table 
    // (ie at this column and row: I'm using this odd form of language so as 
    // to avoid the word "cell" and potential confusion with NSCell), 
    // populated with data from the model 
    NSView* view = [self tableView:aTableView viewForTableColumn:tableColumn row:aRow]; 
    NSAssert([view isKindOfClass:[NSTableCellView class]], @"Expected view used in table to be NSTableCellView"); 
    NSTableCellView* tableCellView = (NSTableCellView*)view; 

    // get the NSCell used by the NSTextField at this position in the table 
    NSCell* cell = [[tableCellView textField] cell]; 

    // See how tall it naturally would want to be if given a restricted width, 
    // but unbound height 
    NSRect unboundHeightColumnRect = NSMakeRect(0, 0, [tableColumn width], CGFLOAT_MAX); 
    CGFloat cellTextHeight = [cell cellSizeForBounds:unboundHeightColumnRect].height; 

    // Apple's docs say this method must return a value greater than 0. 
    // cellTextHeight might be 0 (eg if the model returns no data at this 
    // position in the table). Use the row height set for the table in IB 
    // as the minimum. 
    return MAX(cellTextHeight, [tableView rowHeight]); 
} 
2

Aquí hay otra solución, que funciona bien en mi caso:

Objective-C:

- (double)tableView:(NSTableView *)tableView heightOfRow:(long)row 
{ 
    if (tableView == self.tableViewTodo) 
    { 
     CKRecord *record = [self.arrayTodoItemsFiltered objectAtIndex:row]; 
     NSString *text = record[@"title"]; 

     double someWidth = self.tableViewTodo.frame.size.width; 
     NSFont *font = [NSFont fontWithName:@"Palatino-Roman" size:13.0]; 
     NSDictionary *attrsDictionary = 
     [NSDictionary dictionaryWithObject:font 
            forKey:NSFontAttributeName]; 
     NSAttributedString *attrString = 
     [[NSAttributedString alloc] initWithString:text 
             attributes:attrsDictionary]; 

     NSRect frame = NSMakeRect(0, 0, someWidth, MAXFLOAT); 
     NSTextView *tv = [[NSTextView alloc] initWithFrame:frame]; 
     [[tv textStorage] setAttributedString:attrString]; 
     [tv setHorizontallyResizable:NO]; 
     [tv sizeToFit]; 

     double height = tv.frame.size.height + 20; 

     return height; 
    } 

    else 
    { 
     return 18; 
    } 
} 

Swift:

func tableView(tableView: NSTableView, heightOfRow row: Int) -> CGFloat { 
    if let log:Log = logsArrayController.arrangedObjects.objectAtIndex(row) as? Log { 
     if let string: String = log.message! { 

      let someWidth: CGFloat = tableView.frame.size.width 
      let stringAttributes = [NSFontAttributeName: NSFont.systemFontOfSize(12)] //change to font/size u are using 
      let attrString: NSAttributedString = NSAttributedString(string: string, attributes: stringAttributes) 
      let frame: NSRect = NSMakeRect(0, 0, someWidth, CGFloat.max) 
      let tv: NSTextView = NSTextView(frame: frame) 
      tv.textStorage?.setAttributedString(attrString) 
      tv.horizontallyResizable = false 
      tv.sizeToFit() 
      let height: CGFloat = tv.frame.size.height + 20 // + other objects... 

      return height 

     } 

    } 

    return 100 //Fail 
} 
+0

Gracias! Este es bueno, si sus datos de tabla de visualización están configurados dentro de Interface Builder con enlaces. – Daniel

+0

Este enfoque es útil cuando se usan celdas personalizadas que tienen varios campos de texto editables en una sola columna que contribuyen a la altura de la fila. Como este no es el caso de uso más discutido en la altura de fila variable y dinámica en la Mac, esta respuesta tiene un gran valor. – Chris

Cuestiones relacionadas