Pregunta

Tengo un NSTableView con varias columnas de texto. De forma predeterminada, 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 esté centrado verticalmente en la celda.

Hay una bandera interna en NSTextFieldCell que se puede usar para centrar verticalmente el texto, y funciona de maravilla. Sin embargo, dado que es una bandera interna, su uso no está sancionado por Apple y simplemente podría desaparecer sin previo aviso en una versión futura. Actualmente estoy usando esta bandera interna porque es simple y efectiva. Obviamente, Apple ha pasado algún tiempo implementando la función, por lo que no me gusta la idea de volver a implementarla.

Entonces; mi pregunta es esta: ¿Cuál es la forma correcta de implementar algo que se comporte exactamente como NStextFieldCell de Apple, pero dibuje texto centrado verticalmente en lugar de alineado por arriba?

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

Se usa de la siguiente manera:

[[myTableColumn dataCell] setVerticalCentering:YES];
¿Fue útil?

Solución

Las otras respuestas no funcionaron para varias líneas. Por lo tanto, inicialmente seguí usando la propiedad cFlags.vCentered no documentada, 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 funciona para varias líneas, ajuste de palabras y una última línea truncada:

-(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; agregue una liberación automática después de attrString.mutableCopy si usa la administración de memoria manual)

Otros consejos

Reemplazar -titleRectForBounds de NSCell: debería hacerlo, ese es el método responsable de decirle a la celda dónde 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];
}

Para su información, esto funciona bien, aunque no he logrado mantenerlo centrado cuando edita la celda ... A veces tengo celdas con grandes cantidades de texto y este código puede hacer que se desalineen si el texto la altura es mayor que la celda en la que intenta centrarla verticalmente. Aquí está 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;
}

Para cualquiera que intente esto usando el método drawInteriorWithFrame: inView: de Matt Ball, esto ya no dibujará un fondo si ha configurado su celda para dibujar uno. Para resolver esto, agregue algo similar a

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

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

Aunque esta es una pregunta bastante antigua ...

Creo que el estilo predeterminado de la implementación NSTableView está destinado estrictamente a la visualización de texto de una sola línea con el mismo tamaño & amp; fuente.

En ese caso, recomiendo,

  1. Establecer fuente.
  2. Ajustar rowHeight .

Tal vez obtendrá filas silenciosamente densas. Y luego, déles relleno al configurar intercellSpacing .

Por ejemplo,

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

Aquí lo que obtendrá con dos ajustes de propiedad.

ingrese la descripción de la imagen aquí

Esto no funcionará para texto de varias líneas, pero es lo suficientemente bueno para un centro vertical rápido si no necesita soporte de varias líneas.

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

1) En 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 la altura de su fila es 32, haga que la altura de su celda sea 32

2) Asegúrese de que su celda esté bien colocada en su fila (quiero decir visible)

3) Seleccione su TextField dentro de su Celda y vaya a su inspector de tamaño

4) Debería ver "Organizar" elemento y seleccione " Centrar verticalmente en el contenedor "

- > El TextField se centrará en la celda

No. La forma correcta es colocar el campo en otra vista y usar el diseño automático o el diseño de esa vista principal para colocarlo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top