52

我有NSTableView几个文本列。默认情况下,dataCellfor these columns 是 AppleNSTextFieldCell类的一个实例,它做了各种奇妙的事情,但它绘制的文本与单元格顶部对齐,我希望文本在单元格中垂直居中。

其中有一个内部标志NSTextFieldCell,可用于将文本垂直居中,并且效果很好。但是,由于它是一个内部标志,因此它的使用不受 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];
4

7 回答 7

37

其他答案不适用于多行。因此,我最初继续使用未记录的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 之后添加自动释放)

于 2012-03-03T14:46:54.803 回答
34

覆盖 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];
}
于 2009-08-06T02:17:19.107 回答
5

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

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

到你drawInteriorWithFrame:inView:方法的开始。

于 2010-08-02T22:19:09.010 回答
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;
}
于 2009-08-16T23:47:22.213 回答
3

不。正确的方法是将字段放在另一个视图中并使用自动布局或该父视图的布局来定位它。

于 2014-11-22T15:59:26.603 回答
2

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

我相信 NSTableView 实现的默认样式严格用于具有所有相同大小和字体的单行文本显示。

在这种情况下,我建议,

  1. 设置字体。
  2. 调整rowHeight

也许你会得到安静密集的行。然后,通过设置给他们填充intercellSpacing

例如,

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

在这里你会得到两个属性调整。

在此处输入图像描述

这不适用于多行文本,但如果您不需要多行支持,则足以快速垂直居中。

于 2013-10-19T21:48:22.300 回答
1

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

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

2)确保你的单元格在你的行中很好地放置(我的意思是可见的)

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

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

--> TextField 将在单元格中居中

于 2014-07-10T15:09:38.983 回答