I have an NSTableView
with several text columns. By default, the dataCell
for these columns is an instance of Apple's NSTextFieldCell
class, which does all kinds of wonderful things, but it draws text aligned with the top of the cell, and I want the text to be vertically centered in the cell.
There is an internal flag in NSTextFieldCell
that can be used to vertically center the text, and it works beautifully. However, since it is an internal flag, its use is not sanctioned by Apple and it could simply disappear without warning in a future release. I am currently using this internal flag because it is simple and effective. Apple has obviously spent some time implementing the feature, so I dislike the idea of re-implementing it.
So; my question is this: What is the right way to implement something that behaves exactly like Apple's NStextFieldCell, but draws vertically centered text instead of top-aligned?
For the record, here is my current "solution":
@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
Used as follows:
[[myTableColumn dataCell] setVerticalCentering:YES];
Center the text vertically between the top and bottom margins. Select the text that you want to center. in the Page Setup group, and then click the Layout tab. In the Vertical alignment box, click Center.
The other answers didn't work for multiple lines. Therefore I initially continued using the undocumented cFlags.vCentered
property, but that caused my app to be rejected from the app store. I ended up using a modified version of Matt Bell's solution that works for multiple lines, word wrapping, and a truncated last line:
-(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; }
(This code assumes ARC; add an autorelease after attrString.mutableCopy if you use manual memory management)
Overriding NSCell's -titleRectForBounds:
should do it -- that's the method responsible for telling the cell where to draw its text:
- (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]; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With