NSTextFieldCell vertical alignment, solutions seem to squash the horizontal alignment NSTextFieldCell vertical alignment, solutions seem to squash the horizontal alignment objective-c objective-c

NSTextFieldCell vertical alignment, solutions seem to squash the horizontal alignment


I'm posting this answer to the question since it does work, however, I find the fact that I couldn't find another way to check the alignment setting from IB is very annoying. Accessing _cFlags just seems a little dirty, and I'd love to find a cleaner method.

Based on the code posted earlier from this blog entry.

- (NSRect)drawingRectForBounds:(NSRect)theRect{    // Get the parent's idea of where we should draw    NSRect newRect = [super drawingRectForBounds:theRect];    if (mIsEditingOrSelecting == NO)    {        // Get our ideal size for current text        NSSize textSize = [self cellSizeForBounds:theRect];        // Center that in the proposed rect        float heightDelta = newRect.size.height - textSize.height;          if (heightDelta > 0)        {            newRect.size.height -= heightDelta;            newRect.origin.y += (heightDelta / 2);        }        // For some reason right aligned text doesn't work.  This section makes it work if set in IB.        // HACK: using _cFlags isn't a great idea, but I couldn't find another way to find the alignment.        // TODO: replace _cFlags usage if a better solution is found.        float widthDelta = newRect.size.width - textSize.width;        if (_cFlags.alignment == NSRightTextAlignment && widthDelta > 0) {            newRect.size.width -= widthDelta;            newRect.origin.x += widthDelta;        }    }    return newRect;}


You can use NSParagraphStyle/NSMutableParagraphStyle to set the alignment (and other attributes). Add an appropriately-configured NSParagraphStyle object to the full range of your attributed string.


There are a couple of potential solutions posted in a similar question which I asked a while back.

In all honesty, I still use the undocumented _cFlags.vCentered boolean (tsk tsk, bad programmer!) to get the job done. It's simple, and it works. I'll reinvent the wheel later on if I have to.

update:

OK, I think I've figured it out. Both solutions rely on a call to super to get the default rect, and then modify origin.y and size.height to perform the vertical centering. The calls to super, however, return a rectangle whose width has already been adjusted to fit the text horizontally.

The solution is to use origin.x and size.width from the bounds rect that is passed in to the method:

In solution #1:

- (NSRect)titleRectForBounds:(NSRect)theRect {    NSRect titleFrame = [super titleRectForBounds:theRect];    NSSize titleSize = [[self attributedStringValue] size];    // modified:    theRect.origin.y += (theRect.size.height - titleSize.height)/2.0 - 0.5;    return theRect;}

In solution #2:

- (NSRect)drawingRectForBounds:(NSRect)theRect{    NSRect newRect = [super drawingRectForBounds:theRect];    // modified:    newRect.origin.x = theRect.origin.x;    newRect.size.width = theRect.size.width;    if (mIsEditingOrSelecting == NO)    {        // Get our ideal size for current text        NSSize textSize = [self cellSizeForBounds:theRect];        // Center that in the proposed rect        float heightDelta = newRect.size.height - textSize.height;          if (heightDelta > 0)        {            newRect.size.height -= heightDelta;            newRect.origin.y += (heightDelta / 2);        }    }    return newRect;}