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

e.J*_*mes 50 customization cocoa 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
Run Code Online (Sandbox Code Playgroud)

使用如下:

[[myTableColumn dataCell] setVerticalCentering:YES];
Run Code Online (Sandbox Code Playgroud)

Jak*_*ger 36

其他答案不适用于多行.因此,我最初继续使用未记录的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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 顺便说一句,是否可以在编辑文本时将文本居中?我的`NSTextFieldCell`是多行,当用户双击文本进行编辑时,它会返回到顶部,直到编辑完成. (3认同)
  • 有没有办法在字段中写入时重新显示/重绘文本? (2认同)

Mat*_*all 31

覆盖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];
}
Run Code Online (Sandbox Code Playgroud)

  • @MattBall如果选择了NSTextField中的文本,它将再次返回顶部对齐. (5认同)
  • 啊,我忘记了NSTextFieldCell基本上在于它的文档 - 你是对的,NSTextFieldCell默认情况下不使用-titleRectForBounds:.我已经更新了我的覆盖-drawInteriorWithFrame的回答:inView:为了在正确的位置绘制文本. (3认同)
  • 这对NSTextField中的NSTextFieldCell也有效吗?它似乎不起作用.*编辑*2009?也许它有点老了.:) (2认同)

Gre*_*ton 5

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

[[NSColor lightGrayColor] set];
NSRectFill(cellFrame);
Run Code Online (Sandbox Code Playgroud)

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