2009-08-05 11 views
48

Tengo un NSTableView con varias columnas de texto. Por defecto, el dataCell para estas columnas es una instancia de la clase NSTextFieldCell de Apple, que hace todo tipo de cosas maravillosas, pero dibuja texto alineado con la parte superior de la celda, y quiero que el texto se centre verticalmente en la celda.¿Hay una manera "correcta" de hacer que NSTextFieldCell dibuje texto centrado verticalmente?

Hay una bandera interna en NSTextFieldCell que se puede utilizar para centrar verticalmente el texto, y funciona muy bien. Sin embargo, dado que es una bandera interna, Apple no sanciona su uso y simplemente podría desaparecer sin previo aviso en una versión futura. Actualmente estoy usando esta bandera interna porque es simple y efectiva. Apple obviamente ha dedicado un tiempo a implementar la función, por lo que no me gusta la idea de volver a implementarla.

Así; mi pregunta es la siguiente: ¿Cuál es la forma correcta de implementar algo que se comporta exactamente como NStextFieldCell de Apple, pero dibuja texto centrado verticalmente en lugar de alineado a la parte superior?

Para el registro, aquí está mi "solución" actual:

@interface NSTextFieldCell (MyCategories) 
- (void)setVerticalCentering:(BOOL)centerVertical; 
@end 

@implementation NSTextFieldCell (MyCategories) 
- (void)setVerticalCentering:(BOOL)centerVertical 
{ 
    @try { _cFlags.vCentered = centerVertical ? 1 : 0; } 
    @catch(...) { NSLog(@"*** unable to set vertical centering"); } 
} 
@end 

utiliza como sigue:

[[myTableColumn dataCell] setVerticalCentering:YES]; 
+0

No creo que el bloque try/catch tenga algún sentido en este caso, porque _cflags es una estructura C, no un objeto Objective C. Si se modifica esta estructura en una versión futura de Mac OS X, pueden ocurrir todo tipo de cosas extrañas, pero no se lanzará ninguna excepción. –

+0

@Jakob Egger: Probablemente tengas razón. Encontré esa solución en otra parte de Internet y la copié en el estado en que se encuentra. –

+0

Deberías aceptar la respuesta de Jakob Egger. Cuando se usa el código de la respuesta aceptada, causa un error extraño cuando se edita 'NSTextFieldCell'. La respuesta de Jakob resuelve el problema. –

Respuesta

35

Las otras respuestas no funcionaron para varias líneas. Por lo tanto, inicialmente seguí usando la propiedad no documentada cFlags.vCentered, pero eso provocó que mi aplicación fuera rechazada de la tienda de aplicaciones. Terminé usando una versión modificada de la solución de Matt Bell que trabaja para varias líneas, ajuste de texto, y una truncada última línea:

-(void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 
    NSAttributedString *attrString = self.attributedStringValue; 

    /* if your values can be attributed strings, make them white when selected */ 
    if (self.isHighlighted && self.backgroundStyle==NSBackgroundStyleDark) { 
     NSMutableAttributedString *whiteString = attrString.mutableCopy; 
     [whiteString addAttribute: NSForegroundColorAttributeName 
          value: [NSColor whiteColor] 
          range: NSMakeRange(0, whiteString.length) ]; 
     attrString = whiteString; 
    } 

    [attrString drawWithRect: [self titleRectForBounds:cellFrame] 
        options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin]; 
} 

- (NSRect)titleRectForBounds:(NSRect)theRect { 
    /* get the standard text content rectangle */ 
    NSRect titleFrame = [super titleRectForBounds:theRect]; 

    /* find out how big the rendered text will be */ 
    NSAttributedString *attrString = self.attributedStringValue; 
    NSRect textRect = [attrString boundingRectWithSize: titleFrame.size 
               options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin ]; 

    /* If the height of the rendered text is less then the available height, 
    * we modify the titleRect to center the text vertically */ 
    if (textRect.size.height < titleFrame.size.height) { 
     titleFrame.origin.y = theRect.origin.y + (theRect.size.height - textRect.size.height)/2.0; 
     titleFrame.size.height = textRect.size.height; 
    } 
    return titleFrame; 
} 

(Este código asume ARC, añadir un autorelease después attrString.mutableCopy si utiliza el manual gestión de memoria)

+0

Esto funcionó para mí y es una implementación muy buena, gracias. – ioquatix

+0

Esto funciona muy bien. La respuesta aceptada causó un extraño error al editar la celda. –

+3

Por cierto, ¿es posible centrar el texto cuando se está editando? My 'NSTextFieldCell' tiene varias líneas y, cuando el usuario hace doble clic en el texto para editarlo, vuelve a la parte superior hasta que se completa la edición. –

29

Anulación NSCell de -titleRectForBounds: debería hacerlo - que es el método responsable de decirle a la celda donde dibujar su texto:

- (NSRect)titleRectForBounds:(NSRect)theRect { 
    NSRect titleFrame = [super titleRectForBounds:theRect]; 
    NSSize titleSize = [[self attributedStringValue] size]; 
    titleFrame.origin.y = theRect.origin.y + (theRect.size.height - titleSize.height)/2.0; 
    return titleFrame; 
} 

- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 
    NSRect titleRect = [self titleRectForBounds:cellFrame]; 
    [[self attributedStringValue] drawInRect:titleRect]; 
} 
+0

Esto parece una idea prometedora, pero no funciona para mí. Creé una subclase de 'NSTextFieldCell', copié tu código y usé la clase personalizada para las celdas en mi' NSTableView', pero el método 'titleRectForBounds' nunca se llama. –

+3

Ah, olvidé que NSTextFieldCell básicamente se encuentra en su documentación: tienes razón, NSTextFieldCell de forma predeterminada no usa -titleRectForBounds :. He actualizado mi respuesta para sobrescribir -drawInteriorWithFrame: inView: para dibujar el texto en el lugar correcto. –

+0

Bien hecho. Eso funciona como un encanto! –

4

FYI , esto funciona bien, aunque no he logrado que permanezca centrado cuando editas la celda ... A veces tengo celdas con grandes cantidades de texto y este código puede hacer que se desalineen si la altura del texto es mayor que . la célula que está tratando de centrar verticalmente en este es mi método modificado:

- (NSRect)titleRectForBounds:(NSRect)theRect 
{ 
    NSRect titleFrame = [super titleRectForBounds:theRect]; 
    NSSize titleSize = [[self attributedStringValue] size]; 
    // test to see if the text height is bigger then the cell, if it is, 
    // don't try to center it or it will be pushed up out of the cell! 
    if (titleSize.height < theRect.size.height) { 
     titleFrame.origin.y = theRect.origin.y + (theRect.size.height - titleSize.height)/2.0; 
    } 
    return titleFrame; 
} 
4

para cualquier persona que intente esto utilizando el método de Matt Ball drawInteriorWithFrame:inView:, esto ya no dibujar un plano si ha configurado su celular para llamar uno. Para resolver este añadir algo en la línea de

[[NSColor lightGrayColor] set]; 
NSRectFill(cellFrame); 

al comienzo de su método de drawInteriorWithFrame:inView:.

2

Aunque esto es bastante vieja pregunta ...

creo estilo por defecto de la aplicación NSTableView está destinado exclusivamente para la visualización de texto única línea con toda & mismo tamaño de fuente.

En ese caso, le recomiendo,

  1. conjunto de fuentes.
  2. Ajuste rowHeight.

Tal vez consigas filas silenciosamente densas. Y luego, dales relleno rellenando el intercellSpacing.

Por ejemplo,

core_table_view.rowHeight    = [NSFont systemFontSizeForControlSize:(NSSmallControlSize)] + 4; 
    core_table_view.intercellSpacing  = CGSizeMake(10, 80); 

Aquí lo que se obtiene con dos de ajuste de propiedad.

enter image description here

Esto no funcionará para el texto de varias líneas, pero muy suficientemente bueno para centro vertical rápido si usted no necesita varias líneas de apoyo.

+0

Esa es una solución razonable para celdas de una línea, que probablemente cubre la mayoría de los casos de uso. ¡Gracias! –

1

que tenían el mismo problema y aquí está la solución que hice:

1) En el Interface Builder, seleccione su NSTableCellView. Asegúrese de que sea tan grande como la altura de la fila en el Inspector de tamaño. Por ejemplo, si su altura de fila es 32, que tu teléfono altura de 32

2) Asegúrese de que su celular está bien situado en su fila (me refiero visibles)

3) Seleccione el campo de texto en el interior de la célula e ir a su inspector tamaño

4) Usted debe ver "Organizar" elemento y seleccione "centrar verticalmente en el contenedor"

-> el campo de texto se centrará en sí en la celda

0

No. la forma correcta es para poner el campo en otra vista y usar aut o el diseño o el diseño de la vista principal para posicionarlo.

+0

OK - pero entonces ¿cómo iba a hacer el cambio de tamaño de campo en sí (cambiar su altura) para que coincida con el texto? Sin eso, tendré un campo de texto muy centrado, pero el texto dentro del campo aún estará alineado a la parte superior, por lo que el texto aparecerá sobre el centro en la vista principal. –

+0

Esta es la respuesta correcta. Deje NSTextField a depender de su tamaño intrínseca (ajustar el tamaño de la fuente como se prefiere, que corresponderá a un cambio en el tamaño intrínseco), a continuación, agregarlo como una vista secundaria a una vista contenedor que enmarcarlo en relación a lo que sostiene el campo de texto y eso enmarca el tamaño intrínseco del campo de texto en relación con el espacio total. – Asher

+0

@Asher, en realidad no, cambiar el tamaño de la fuente no hace que el campo cambie de tamaño: https://www.dropbox.com/s/9b4vgcp7kuujll2/Screenshot%202016-03-01%2012.02.26.png?dl=0 –

Cuestiones relacionadas