Is there a “right” way to have NSTextFieldCell draw vertically centered text?

蹲街弑〆低调 提交于 2019-11-27 02:46:01

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];
}

For anyone attempting this using Matt Ball's drawInteriorWithFrame:inView: method, this will no longer draw a background if you have set your cell to draw one. To solve this add something along the lines of

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

to the beginning of your drawInteriorWithFrame:inView: method.

FYI, this works well, although I haven't managed to get it to stay centered when you edit the cell... I sometimes have cells with large amounts of text and this code can result in them being misaligned if the text height is greater then the cell it's trying to vertically center it in. Here's my modified method:

- (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;
}

Though this is pretty old question...

I believe default style of NSTableView implementation is intended strictly for single line text display with all same size & font.

In that case, I recommend,

  1. Set font.
  2. Adjust rowHeight.

Maybe you will get quietly dense rows. And then, give them padding by setting intercellSpacing.

For example,

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

Here what you'll get with two property adjustment.

This won't work for multi-line text, but very good enough for quick vertical center if you don't need multi-line support.

I had the same problem and here is the solution I did :

1) In Interface Builder, select your NSTableCellView. Make sure it as big as the row height in the Size Inspector. For example, if your row height is 32, make your Cell height 32

2) Make sure your cell is well placed in your row (I mean visible)

3) Select your TextField inside your Cell and go to your size inspector

4) You should see "Arrange" item and select "Center Vertically in Container"

--> The TextField will center itself in the cell

No. The right way is to put the Field in another view and use auto layout or that parent view's layout to position it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!