Center vertically in UILabel with autoshrink
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 toYES
, 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 isUIBaselineAdjustment
AlignBaselines
. This property is effective only when thenumberOfLines
property is set to1
.
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
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];
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.

Comments
-
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 theUILabel
. 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.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!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 almost 10 yearsUse 'NSTextAlignmentCenter' for targeting iOS6!
-
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 almost 10 yearsIt's working in my test app. Can you create a simple test case to sleuth it out? Or I could post mine.
-
Paul Cezanne almost 10 yearsI 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 almost 10 yearswell, 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 almost 10 yearsHmmm, 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 almost 10 yearsok, 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 almost 10 yearsit 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 about 9 years@TomSwift I'd upvote this answer 10000 times if I could. Thanks!
-
Kamran Khan over 8 yearsalso, make sure lineBreakMode is not "Word Wrap"
-
C0D3 about 8 yearsThis isn't what he was asking.
-
narco over 6 yearscenters horizontally not vertically
-
andrii over 3 yearsthe Most elegant solution!