I’ve been bothered for a long time by a limitation of NSTextFieldCell that prevents developers from specifying a vertically centered alignment. This is particular annoying in contexts where Apple practically rolls out the red carpet for a particular UI feature, but where taking advantage of that feature is almost guaranteed to produce an ugly result. Take NSTableView for example. What is the most common cell type in a table? NSTextFieldCell of course. But what happens when you add the slightest bit of creativity to a table, say by changing the row height to a value not suited to the font size?
That’s bad enough, but let’s say you find good reason to reach for even taller table columns? It can only get worse from here:
In the past I’ve just worked around this problem by finding another way to present my UI. In other words: just keep the freakin’ table view rows shallow, or else live with the funny looking top-alignment of the text. Today I got fed up with that and decided to shoot for a general-purpose solution.
I didn’t want to implement my own completely custom text cell. NSTextFieldCell is pretty good, you know! It does a lot for me, and I’d like to continue taking advantage of that. Through a bit of experimentation, I discovered that I could make a pretty minor tweak to NSTextFieldCell and get the behavior I wanted. By overriding “drawingRectForBounds:” and returning, instead of the whole lot of real estate available to me, a centered subset of that area, I convinced AppKit to render the text in the middle like I wanted it:
Hey! That’s looking a lot better. I like it. It looks pretty. You know, like a Mac. But you know what doesn’t look pretty? When I double-click this bad boy and try to edit the text:
Ouch! That’s a pretty freaky looking user experience. Apparently NSTextFieldCell or some other component of AppKit is not used to having the drawing rect drastically adjusted without its knowledge. I might have to call this whole deal off. However bad top-aligned text in my table cell is, it’s a bajillion times less offensive than that. But then I realized that as a cell, I am given a lot of control over the edit process. What if I can limit my rect adjustment so that it’s normal while we’re editing, but weird (i.e. good) all the rest of the time?
I added two methods to my custom subclass, overriding “selectWithFrame:…” and “editWithFrame:…”. In these methods, I use my rect calculation method to transform the proposed edit or selection rect into the more desirable “centered rect,” then I set a flag in the class “mIsEditingOrSelecting” which tells my rect calculator to stop the funny business. The result is an NSTextFieldCell with very little code that, as far as I can tell, behaves appropriately in all circumstances:
Good enough for beta software! But here’s where you come in. You want this sexy vertically aligned cell for your app, right? So let’s share and figure out whether it’s monumentally busted or not.
Download RSVerticallyCenteredTextFieldCell. MIT License. Pop it into your project and, upon waking from nib, set your text column data cells (or other text field cells, if you have good reason) to instances of it. Let me know if you spot any bugs!