Objective c 在NSTextField中设置文本垂直中心

Objective c 在NSTextField中设置文本垂直中心,objective-c,macos,cocoa,Objective C,Macos,Cocoa,在特定高度的NSTextField中,如果文本的大小很小,则布局将如下所示 文本流向顶部,如何使文本中心如下: 只是子类NSTextFieldCell()。。。并实施 - (NSRect) titleRectForBounds:(NSRect)frame { CGFloat stringHeight = self.attributedStringValue.size.height; NSRect titleRect = [super titleRe

在特定高度的NSTextField中,如果文本的大小很小,则布局将如下所示

文本流向顶部,如何使文本中心如下:


只是子类
NSTextFieldCell
()。。。并实施

- (NSRect) titleRectForBounds:(NSRect)frame {  

  CGFloat stringHeight       = self.attributedStringValue.size.height;
   NSRect titleRect          = [super titleRectForBounds:frame];
          titleRect.origin.y = frame.origin.y + 
                              (frame.size.height - stringHeight) / 2.0;
   return titleRect;
 }
- (void) drawInteriorWithFrame:(NSRect)cFrame inView:(NSView*)cView {
  [super drawInteriorWithFrame:[self titleRectForBounds:cFrame] inView:cView];
 }

我基本上是在使用Alex的答案,但有一个修正:如果我们增加y原点,我们应该减少标题的高度。否则,我们的titleRect将在其superview的末尾下方结束,可能会隐藏NSTextField下方的任何内容

A.h:

#import <Cocoa/Cocoa.h>

@interface VerticallyCenteredTextFieldCell : NSTextFieldCell

@end
另外,VerticallyCenteredTextFieldCell是NSTextFieldCell的一个子类。如果将其子类化,请在Interface Builder中更改NSTextFieldCell的类,而不是NSTextField(我不知道这一点)


埃里克·韦格纳答案的Swift版本(也修改为多行):


除了Erik和Hejazi的答案之外,您还需要实现
selectWithFrame
,以下是Swift 2.2中的解决方案:

class VerticallyCenteredTextFieldCell: NSTextFieldCell {
    override func titleRectForBounds(rect: NSRect) -> NSRect {
        var titleRect = super.titleRectForBounds(rect)

        let minimumHeight = self.cellSizeForBounds(rect).height
        titleRect.origin.y += (titleRect.height - minimumHeight) / 2
        titleRect.size.height = minimumHeight

        return titleRect
    }

    override func drawInteriorWithFrame(cellFrame: NSRect, inView controlView: NSView) {
        super.drawInteriorWithFrame(titleRectForBounds(cellFrame), inView: controlView)
    }

    override func selectWithFrame(aRect: NSRect, inView controlView: NSView, editor textObj: NSText, delegate anObject: AnyObject?, start selStart: Int, length selLength: Int) {
        super.selectWithFrame(titleRectForBounds(aRect), inView: controlView, editor: textObj, delegate: anObject, start: selStart, length: selLength);
    }
}

我的解决方案基于使用NSLayoutManager计算字体高度。 这种方法允许使用属性字符串的方法计算高度,从而获得更高的性能

- (NSRect)titleRectForBounds:(NSRect)theRect {
    NSRect titleFrame = [super titleRectForBounds:theRect];

    CGFloat fontHeight = [[[NSLayoutManager alloc] init] defaultLineHeightForFont:self.font];
    if (fontHeight < titleFrame.size.height) {
        titleFrame.origin.y = theRect.origin.y + (theRect.size.height - fontHeight) * 0.5f;
        titleFrame.size.height = fontHeight;
    }
    return titleFrame;
}

- (void) drawInteriorWithFrame:(NSRect)frame inView:(NSView *)view {
    [super drawInteriorWithFrame:[self titleRectForBounds:frame] inView:view];
}
-(NSRect)标题rectforbounds:(NSRect)theRect{
NSRect titleFrame=[super titleRectForBounds:theRect];
CGFloat fontHeight=[[NSLayoutManager alloc]init]defaultLineHeightForFont:self.font];
if(字体高度<标题框大小高度){
titleFrame.origin.y=修正后的origin.y+(修正后的size.height-字体高度)*0.5f;
titleFrame.size.height=字体高度;
}
返回标题框;
}
-(无效)drawInteriorWithFrame:(NSRect)frame inView:(NSView*)视图{
[super drawInteriorWithFrame:[self-titleRectForBounds:frame]查看:查看];
}

可能重复的,请查看@非常感谢,它可以工作,但是如果选择了NSTextField中的文本,它将重新回到顶部对齐。@Veelian这方面有什么进展吗?我得到了同样的结果,当用户输入文本时,它是顶部对齐的,然后当他们单击另一个字段时,它会跳回centered@Vervious很抱歉没有很好的解决方案。请注意,这些是
NSTextFieldCell
的实例方法,而不是
NSTextField
。我在
NSTextFieldCell
上添加了一个类别,并实现了这些方法,效果非常好。Swizzle??你在开玩笑吧?提出这样的建议来解决这样的问题显然是不道德的。如果textfield有多行,这段代码就不能正常工作。我有我的3和最后一行根本没有显示。我在10.10上。@Yar这个答案不是,但它包含一个指向需要使用方法swizzling的解决方案的链接。帮了我很多忙,谢谢!一个建议:如果增加y原点,则减小标题栏的高度,否则标题栏将超出其superview。当您输入TF进行编辑时,文本将切换回顶部。您的意思是您还需要实现
selectWithFrame
?这不是在Xib中设置子类的目的,但没有调用titleRectForBounds方法。
class VerticallyCenteredTextFieldCell: NSTextFieldCell {
    override func titleRectForBounds(rect: NSRect) -> NSRect {
        var titleRect = super.titleRectForBounds(rect)

        let minimumHeight = self.cellSizeForBounds(rect).height
        titleRect.origin.y += (titleRect.height - minimumHeight) / 2
        titleRect.size.height = minimumHeight

        return titleRect
    }

    override func drawInteriorWithFrame(cellFrame: NSRect, inView controlView: NSView) {
        super.drawInteriorWithFrame(titleRectForBounds(cellFrame), inView: controlView)
    }

    override func selectWithFrame(aRect: NSRect, inView controlView: NSView, editor textObj: NSText, delegate anObject: AnyObject?, start selStart: Int, length selLength: Int) {
        super.selectWithFrame(titleRectForBounds(aRect), inView: controlView, editor: textObj, delegate: anObject, start: selStart, length: selLength);
    }
}
class CustomTextFieldCell: NSTextFieldCell {

    func adjustedFrame(toVerticallyCenterText rect: NSRect) -> NSRect {
        // super would normally draw text at the top of the cell
        var titleRect = super.titleRect(forBounds: rect)

        let minimumHeight = self.cellSize(forBounds: rect).height
        titleRect.origin.y += (titleRect.height - minimumHeight) / 2
        titleRect.size.height = minimumHeight

        return titleRect
    }

    override func edit(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, event: NSEvent?) {
        super.edit(withFrame: adjustedFrame(toVerticallyCenterText: rect), in: controlView, editor: textObj, delegate: delegate, event: event)
    }

    override func select(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, start selStart: Int, length selLength: Int) {
        super.select(withFrame: adjustedFrame(toVerticallyCenterText: rect), in: controlView, editor: textObj, delegate: delegate, start: selStart, length: selLength)
    }

    override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
        super.drawInterior(withFrame: adjustedFrame(toVerticallyCenterText: cellFrame), in: controlView)
    }

    override func draw(withFrame cellFrame: NSRect, in controlView: NSView) {
        super.draw(withFrame: cellFrame, in: controlView)
    }
}
- (NSRect)titleRectForBounds:(NSRect)theRect {
    NSRect titleFrame = [super titleRectForBounds:theRect];

    CGFloat fontHeight = [[[NSLayoutManager alloc] init] defaultLineHeightForFont:self.font];
    if (fontHeight < titleFrame.size.height) {
        titleFrame.origin.y = theRect.origin.y + (theRect.size.height - fontHeight) * 0.5f;
        titleFrame.size.height = fontHeight;
    }
    return titleFrame;
}

- (void) drawInteriorWithFrame:(NSRect)frame inView:(NSView *)view {
    [super drawInteriorWithFrame:[self titleRectForBounds:frame] inView:view];
}