cocoa - ¿Hay una manera "correcta" de hacer que NSTextFieldCell dibuje texto centrado verticalmente?
customization vertical-alignment (7)
Tengo un NSTableView
con varias columnas de texto. Por defecto, la dataCell
de 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 un indicador interno en NSTextFieldCell
que se puede usar 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.
Asi que; mi pregunta es esta: ¿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 alineados al principio?
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
Utilizado de la siguiente manera:
[[myTableColumn dataCell] setVerticalCentering:YES];
Aunque esta es una pregunta bastante antigua ...
Creo que el estilo predeterminado de la implementación de NSTableView está destinado estrictamente a la visualización de texto de una sola línea con el mismo tamaño y fuente.
En ese caso, recomiendo,
- Establecer fuente.
- Ajuste
rowHeight
.
Tal vez consigas filas silenciosamente densas. Y luego, dales relleno ajustando 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.
Esto no funcionará para textos de varias líneas, pero es lo suficientemente bueno para un centro vertical rápido si no necesita soporte de varias líneas.
Las otras respuestas no funcionaron para múltiples líneas. Por lo tanto, inicialmente seguí usando la propiedad cFlags.vCentered
no 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 funciona para múltiples 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 que ARC; agrega una liberación automática después de attrString.mutableCopy si usa la administración manual de la memoria)
No. La forma correcta es colocar el campo en otra vista y usar el diseño automático o el diseño de la vista principal para colocarlo.
Para cualquiera que intente esto utilizando el drawInteriorWithFrame:inView:
Matt Ball, esto ya no dibujará un fondo si ha configurado su celda para dibujar uno. Para resolver esto, agregue algo a lo largo de las líneas de
[[NSColor lightGrayColor] set];
NSRectFill(cellFrame);
al comienzo de su drawInteriorWithFrame:inView:
método.
Para tu información, 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. entonces la celda está tratando de 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;
}
Reemplazando NSCell -titleRectForBounds:
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];
}
Tuve el mismo problema y aquí está la solución que hice:
1) En Interface Builder, selecciona tu 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 su celda tenga una altura de 32
2) Asegúrate de que tu celda esté bien ubicada en tu fila (me refiero a visible)
3) Seleccione su campo de texto dentro de su celda y vaya a su inspector de tamaño
4) Debería ver el elemento "Organizar" y seleccionar "Centrar verticalmente en el contenedor"
-> The TextField se centrará en la celda