Center vertically in UILabel with autoshrink

25,312

Solution 1

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

Solution 2

when working in IB, be sure to set align baselines to center

enter image description here

Note: line break CANNOT be word wrap for this to work, so it will NOT work multiline (good to set the line break to Truncate tail)

Solution 3

-(void)fitVerticallyToLabel:(UILabel *)lbl
{
    CGFloat fontSize = lbl.frame.size.width / lbl.text.length;
    [lbl setFont:[UIFont fontWithName:@"Helvetica-Bold" size:fontSize]];
    CGRect rect = lbl.frame;
    rect.origin.y += rect.size.height - fontSize;
    rect.size.height = fontSize;
    [lbl setFrame:rect];
}

How to Use: Call this method after setting the text to your label.

    label.text = @"text";
    [self fitVerticallyToLabel:label];

enter image description hereenter image description here

Note: I ahev taken UILabel from xib. You can take it programmatically too in that case you will have to set its text alignment NSTextAlignMentCenter

Solution 4

Try to implement this logic:

-(void)adjustLabel1Text1:(NSString *)text1 
{
    UILabel *lbl_first = [UIFont fontWithName:@"Helvetica" size:12];
    text1 = [text1 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    float hedingLblHeight = [self calculateHeightOfTextFromWidth:text1 : [UIFont fontWithName:@"Helvetica" size:12] :118 :UILineBreakModeWordWrap];
    lbl_first.text=text1;
    [lbl_first setFrame:CGRectMake(lbl_first.frame.origin.x, lbl_first.frame.origin.y, 118, hedingLblHeight)];
    lbl_first.lineBreakMode = UILineBreakModeWordWrap;
    lbl_first.numberOfLines = 0;
    [lbl_first sizeToFit];
//////////Adjust the lable or any UIControl below this label accordingly.
    float endResultHeight=[self calculateHeightOfTextFromWidth:text2 : [UIFont fontWithName:@"Helvetica" size:15] :299 :UILineBreakModeWordWrap];
    if(hedingLblHeight>secondImgTitleHeight)
    {
    [lbl_endResult setFrame:CGRectMake(lbl_endResult.frame.origin.x, lbl_first.frame.origin.y+lbl_first.frame.size.height+5, 299, endResultHeight)];
    }
    else
    {
        [lbl_endResult setFrame:CGRectMake(lbl_endResult.frame.origin.x, lbl_first.frame.origin.y+lbl_first.frame.size.height+5, 299, endResultHeight)];
    }
    lbl_endResult.lineBreakMode=UILineBreakModeWordWrap;
    lbl_endResult.numberOfLines = 0;
    [lbl_endResult sizeToFit];
}
-(float) calculateHeightOfTextFromWidth:(NSString*)text : (UIFont*) withFont:(float)width :(UILineBreakMode)lineBreakMode
{
    CGSize suggestedSize = [text sizeWithFont:withFont constrainedToSize:CGSizeMake(width, FLT_MAX) lineBreakMode:lineBreakMode];
    return suggestedSize.height;
}

It has helped me a lot.Hope it works for you.

Share:
25,312
Paul Cezanne
Author by

Paul Cezanne

oblique @ alum dot mit dot edu SOreadytohelp

Updated on July 09, 2022

Comments

  • Paul Cezanne
    Paul Cezanne 11 months

    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.)

  • JFS
    JFS almost 10 years
    Use 'NSTextAlignmentCenter' for targeting iOS6!
  • Tricertops
    Tricertops almost 10 years
    +1 This is correct way. Many answers trying to calculate the frame manually, but it's this simple. And it's available in iOS 2.0 and later.
  • TomSwift
    TomSwift almost 10 years
    It's working in my test app. Can you create a simple test case to sleuth it out? Or I could post mine.
  • Paul Cezanne
    Paul Cezanne almost 10 years
    I can send you the whole source code if you want, it is pretty small, just an exercise time. oblique at alum dot mit dot edu
  • TomSwift
    TomSwift almost 10 years
    well, I really don't want your source. but I'll update my answer with my test-case and you can go from there.
  • Paul Cezanne
    Paul Cezanne almost 10 years
    Hmmm, it looks awfully similar to my code, the only difference in mine is that my view controller is contained in another view controller, but I have a hard time believing that that matters.
  • Paul Cezanne
    Paul Cezanne almost 10 years
    ok, I'll mark this correct since I'm sure you did the heavy lifting, but your missing one more part. My UILabels came from InterfaceBuilder which had "Tighten Letter Spacing" turn ON. Turning that off, with the above code, does the trick. If you could modify your answer that would be awesome. And thanks for sticking with me!
  • TomSwift
    TomSwift almost 10 years
    it seems that using adjustsLetterSpacingToFitWidth breaks baselineAdjustment. I don't see this documented anywhere; probably merits filing a radar bug with Apple. I'll do that.
  • Francesco Puglisi
    Francesco Puglisi about 9 years
    @TomSwift I'd upvote this answer 10000 times if I could. Thanks!
  • Kamran Khan
    Kamran Khan over 8 years
    also, make sure lineBreakMode is not "Word Wrap"
  • C0D3
    C0D3 about 8 years
    This isn't what he was asking.
  • narco
    narco over 6 years
    centers horizontally not vertically
  • andrii
    andrii over 3 years
    the Most elegant solution!