Center vertically in UILabel with autoshrink

Paul Cezanne picture Paul Cezanne · Jul 31, 2013 · Viewed 23.9k times · Source

This is a little different from all the other "How do I center the text in a UILabel" questions here...

I have a UILabel with some text in it, I want to center the text vertically in the UILabel. What's the big deal, right? That's the default. The problem comes because my text is dynamic and I have autoshrink turn on. As the text grows larger, the font size shrinks. You get this behavior.

enter image description here

Notice that the font baseline has not moved, I want it to move so the numbers are centered vertically in the UILabel's frame.

Easy, right? I just remember the frame's original center in viewDidLoad

    self.workoutTimeCenter = _workoutTimeLabel.center;

and then I call sizeToFit after I change the the text, right?

    [_workoutTimeLabel sizeToFit];
    _workoutTimeLabel.center = _workoutTimeCenter;

Well, sizeToFit did, I guess, exactly what it was supposed to do, resize the frame so the text fits without shrinking!

enter image description here

How can I vertically center the text in a UILabel while respecting baselines and autoshrink? (Note, an iOS5 and later solution is fine and I can even deal with an iOS6 and later solution.)

Answer

TomSwift picture TomSwift · Aug 6, 2013

In my experience you can just set the -[UILabel baselineAdjustment] property to UIBaselineAdjustmentAlignCenters to achieve the effect you're describing.

From the docs:

baselineAdjustment

Controls how text baselines are adjusted when text needs to shrink to fit in the label.

@property(nonatomic) UIBaselineAdjustment baselineAdjustment

Discussion

If the adjustsFontSizeToFitWidth property is set to YES, this property controls the behavior of the text baselines in situations where adjustment of the font size is required. The default value of this property is UIBaselineAdjustmentAlignBaselines. This property is effective only when the numberOfLines property is set to 1.

and

UIBaselineAdjustmentAlignCenters
Adjust text based relative to the center of its bounding box.

EDIT: adding a full view-controller that demonstrates this:

@interface TSViewController : UIViewController
@end

@implementation TSViewController

- (void) addLabelWithFrame: (CGRect) f baselineAdjustment: (UIBaselineAdjustment) bla
{
    UILabel* label = [[UILabel alloc] initWithFrame: f];
    label.baselineAdjustment = bla;
    label.adjustsFontSizeToFitWidth = YES;
    label.font = [UIFont fontWithName: @"Courier" size: 200];
    label.text = @"00";
    label.textAlignment = NSTextAlignmentCenter;
    label.backgroundColor = [UIColor lightGrayColor];
    label.userInteractionEnabled = YES;
    [self.view addSubview: label];

    UIView* centerline = [[UIView alloc] initWithFrame: CGRectMake(f.origin.x, f.origin.y+(f.size.height/2.0), f.size.width, 1)];
    centerline.backgroundColor = [UIColor redColor];
    [self.view addSubview: centerline];

    UITapGestureRecognizer* tgr = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(onTap:)];
    [label addGestureRecognizer: tgr];
}

- (void) viewDidLoad
{
    [super viewDidLoad];

    [self addLabelWithFrame: CGRectMake(0, 0, 320, 200)
         baselineAdjustment: UIBaselineAdjustmentAlignCenters];

    [self addLabelWithFrame: CGRectMake(0, 220, 320, 200)
         baselineAdjustment: UIBaselineAdjustmentAlignBaselines];
}

- (void) onTap: (UITapGestureRecognizer*) tgr
{
    UILabel* label = (UILabel*)tgr.view;
    NSString* t = [label.text stringByAppendingString: @":00"];
    label.text = t;
}

@end