13

I have an NSTextField and I want to vertically center align the text in it. Basically I need the NSTextField answer of How do I vertically center UITextField Text?

Anyone got some pointers? Thanks!

Community
  • 1
  • 1
simon.d
  • 2,471
  • 3
  • 33
  • 51

3 Answers3

19

You could subclass NSTextFieldCell to do what you want:

MDVerticallyCenteredTextFieldCell.h:

#import <Cocoa/Cocoa.h>

@interface MDVerticallyCenteredTextFieldCell : NSTextFieldCell {

}

@end

MDVerticallyCenteredTextFieldCell.m:

#import "MDVerticallyCenteredTextFieldCell.h"

@implementation MDVerticallyCenteredTextFieldCell

- (NSRect)adjustedFrameToVerticallyCenterText:(NSRect)frame {
    // super would normally draw text at the top of the cell
    NSInteger offset = floor((NSHeight(frame) - 
           ([[self font] ascender] - [[self font] descender])) / 2);
    return NSInsetRect(frame, 0.0, offset);
}

- (void)editWithFrame:(NSRect)aRect inView:(NSView *)controlView
         editor:(NSText *)editor delegate:(id)delegate event:(NSEvent *)event {
    [super editWithFrame:[self adjustedFrameToVerticallyCenterText:aRect]
          inView:controlView editor:editor delegate:delegate event:event];
}

- (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView
                 editor:(NSText *)editor delegate:(id)delegate 
                  start:(NSInteger)start length:(NSInteger)length {

    [super selectWithFrame:[self adjustedFrameToVerticallyCenterText:aRect]
                    inView:controlView editor:editor delegate:delegate
                     start:start length:length];
}

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

@end

You can then use a regular NSTextField in Interface Builder, and specify MDVerticallyCenteredTextFieldCell (or whatever you want to name it) as the custom class for the text field's text field cell (select the textfield, pause, then click the textfield again to select the cell inside the text field):

enter image description here

NSGod
  • 22,699
  • 3
  • 58
  • 66
  • this is great except it's causing the text to spill outside the textfield frame on the left and right sides. any ideas? – simon.d Dec 25 '11 at 02:38
  • @simon.d: right you are... Hmm. I've been using this code (which I believe is adapted from some Apple sample code I found somewhere) for a while without issues, though I realize now it was only with single-line (non-wrapping) `NSTextField`s. I'll take another look at it to see if I can't get it working for multi-line text fields as well... – NSGod Dec 25 '11 at 20:54
5

Swift 3.0 version (Create a custom subclass for NSTextFieldCell):

override func drawingRect(forBounds rect: NSRect) -> NSRect {
    var newRect = super.drawingRect(forBounds: rect)
    let textSize = self.cellSize(forBounds: rect)
    let heightDelta = newRect.size.height - textSize.height
    if heightDelta > 0 {
        newRect.size.height -= heightDelta
        newRect.origin.y += (heightDelta / 2)
    }
    return newRect
}
Beninho85
  • 3,273
  • 27
  • 22
2

It's better to use boundingRectForFont and the function ceilf() when calculating possible maximum font height, because the above-mentioned solution causes text to be cut off under the baseline. So the adjustedFrameToVerticallyCenterText: will look like this

- (NSRect)adjustedFrameToVerticallyCenterText:(NSRect)rect {
    CGFloat fontSize = self.font.boundingRectForFont.size.height;
    NSInteger offset = floor((NSHeight(rect) - ceilf(fontSize))/2);
    NSRect centeredRect = NSInsetRect(rect, 0, offset);
    return centeredRect;
}