是否有一种“正确”的方式让NSTextFieldCell绘制垂直居中的文本?

时间:2009-08-05 19:25:02

标签: cocoa customization vertical-alignment nstextfieldcell

我有一个NSTableView,其中有几个文本列。默认情况下,这些列的dataCell是Apple的NSTextFieldCell类的一个实例,它可以执行各种奇妙的操作,但它会绘制与单元格顶部对齐的文本,并且我希望文本为在细胞中垂直居中。

NSTextFieldCell中有一个内部标记,可用于垂直居中文本,并且效果很好。但是,由于它是一个内部标志,它的使用不受Apple的批准,它可能会在未来的版本中消失而不会发出警告。我目前正在使用这个内部标志,因为它简单而有效。 Apple显然花了一些时间来实现这个功能,所以我不喜欢重新实现它的想法。

因此;我的问题是:实现与Apple的NStextFieldCell完全相同的行为的正确方法是什么,但是绘制垂直居中的文本而不是顶部对齐?

记录中,这是我目前的“解决方案”:

@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

使用如下:

[[myTableColumn dataCell] setVerticalCentering:YES];

7 个答案:

答案 0 :(得分:35)

其他答案不适用于多行。因此,我最初继续使用未记录的cFlags.vCentered属性,但这导致我的应用程序被拒绝从应用程序商店。我最终使用了Matt Bell解决方案的修改版本,该解决方案适用于多行,自动换行和截断的最后一行:

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

(此代码假定ARC;如果使用手动内存管理,则在attrString.mutableCopy之后添加自动释放)

答案 1 :(得分:30)

覆盖NSCell的-titleRectForBounds:应该这样做 - 这是负责告诉单元格在哪里绘制文本的方法:

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

答案 2 :(得分:4)

仅供参考,这种方法效果很好,虽然我在编辑单元格时没有设法让它保持居中...我有时会有大量文本的单元格,这些代码可能导致它们在文本中未对齐高度大于它试图垂直居中的单元格。这是我修改过的方法:

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

答案 3 :(得分:4)

对于使用Matt Ball的drawInteriorWithFrame:inView:方法尝试此操作的任何人,如果您已将单元格设置为绘制一个,则将不再绘制背景。为了解决这个问题,增加了

的内容
[[NSColor lightGrayColor] set];
NSRectFill(cellFrame);

drawInteriorWithFrame:inView:方法的开头。

答案 4 :(得分:2)

虽然这是一个很老的问题......

我相信NSTableView实现的默认样式主要用于单行文本显示,具有相同的大小和尺寸。字体。

在这种情况下,我建议,

  1. 设置字体。
  2. 调整rowHeight
  3. 也许你会得到安静的密集行。然后,通过设置intercellSpacing给他们填充。

    例如,

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

    这里有两项物业调整你会得到的。

    enter image description here

    这不适用于多行文本,但如果您不需要多行支持,则非常适合快速垂直中心。

答案 5 :(得分:1)

我遇到了同样的问题,这是我做的解决方案:

1)在Interface Builder中,选择您的NSTableCellView。确保它与Size Inspector中的行高一样大。例如,如果行高为32,则使单元格高度为32

2)确保你的细胞放在你的行中(我的意思是可见)

3)在Cell中选择TextField并转到尺寸检查器

4)您应该看到“排列”项目并选择“在容器中垂直居中”

- &GT; TextField将自身置于单元格

答案 6 :(得分:1)

没有。正确的方法是将Field放在另一个视图中,并使用自动布局或父视图的布局来定位它。