12

I have been reading through the various options on how to set the vertical alignment on an NSTextField. I want the text to be displayed in the center and to do it programatically in Swift. Here are the things I have looked so far:

One thing I have tried in Swift is to set the following property:

textField.usesSingleLineMode = true

Any tips on the best way to vertically center text would be much appreciated!

Community
  • 1
  • 1
Richard Burton
  • 2,230
  • 6
  • 34
  • 49
  • link: https://stackoverflow.com/questions/1235219/is-there-a-right-way-to-have-nstextfieldcell-draw-vertically-centered-text – BB9z Feb 26 '19 at 08:32

5 Answers5

8

This is very hard to do, as Apple makes this very difficult. I achieved it by subclassing NSTextFieldCell and overriding the drawingRectForBounds: method like so:

override func drawingRectForBounds(theRect: NSRect) -> NSRect {
    let newRect = NSRect(x: 0, y: (theRect.size.height - 22) / 2, width: theRect.size.width, height: 22)
    return super.drawingRectForBounds(newRect)
}

This is just my way to do it, I'm sure there are better ways, which I don't know (yet). And this only works for the standard font size in TextFields (which gives a text height of 22). That's why I hardcoded that. Haven't figured out yet, how to get the height in the cell if you change the font.

Result:

enter image description here

ICL1901
  • 7,632
  • 14
  • 90
  • 138
Andreas Utzinger
  • 392
  • 2
  • 12
4

Try this on a playground, it centers the text perfectly, use it on your projects! Hope it helps!

import Cocoa

let cell = NSTableCellView()
cell.frame = NSRect(x: 0, y: 0, width: 100, height: 100)
let tf = NSTextField()
tf.frame = cell.frame
tf.stringValue = "MyTextfield"
tf.alignment = .Center

let stringHeight: CGFloat = tf.attributedStringValue.size().height
let frame = tf.frame
var titleRect:  NSRect = tf.cell!.titleRectForBounds(frame)

titleRect.size.height = stringHeight + ( stringHeight - (tf.font!.ascender + tf.font!.descender ) )
titleRect.origin.y = frame.size.height / 2  - tf.lastBaselineOffsetFromBottom - tf.font!.xHeight / 2
tf.frame = titleRect
cell.addSubview(tf)
Rafa Febrer
  • 184
  • 14
3

I have added the NSTextField inside a NSView and centered it.

Another solution was (in an iOS project) to create a UILabel and allow it adjust its size (sizeToFit()) and again embed it inside a UIView.

I personally don't like the calculations in previous answers and the second solution for iOS works for all texts size and row numbers.

Darkwonder
  • 1,149
  • 1
  • 13
  • 26
3

I was also facing vertical alignment issue with NSTextField. My requirement involved, rendering a single-line string inside a NSTextField. Additionally, textfield needed to be resize implying we had programatically resized the font-point-size of the text inside text-field on resize. In this scenario we faced vertical-alignment issues - the mis-alignment was tough to grasp/understand in a straight forward way.

What finally worked:

So, in my scenario a simple, turn off the "Single Line Mode" in interface builder
for the text-field solved the issue.

Arjun
  • 379
  • 2
  • 12
  • That’s what worked for me, too. None of the suggested subclassing approaches worked quite right—text was sometimes clipped. – Chris Page May 11 '20 at 18:35
2

The accepted answer works perfectly and here's the Swift3 version.

class VerticallyAlignedTextFieldCell: NSTextFieldCell {
    override func drawingRect(forBounds rect: NSRect) -> NSRect {
        let newRect = NSRect(x: 0, y: (rect.size.height - 22) / 2, width: rect.size.width, height: 22)
        return super.drawingRect(forBounds: newRect)
    }
}
halfer
  • 19,824
  • 17
  • 99
  • 186
emreoktem
  • 2,409
  • 20
  • 36