2340

I have a UILabel with space for two lines of text. Sometimes, when the text is too short, this text is displayed in the vertical center of the label.

How do I vertically align the text to always be at the top of the UILabel?

image representing a UILabel with vertically-centered text

1

51 Answers 51

2777

There's no way to set the vertical-align on a UILabel, but you can get the same effect by changing the label's frame. I've made my labels orange so you can see clearly what's happening.

Here's the quick and easy way to do this:

    [myLabel sizeToFit];

sizeToFit to squeeze a label


If you have a label with longer text that will make more than one line, set numberOfLines to 0 (zero here means an unlimited number of lines).

    myLabel.numberOfLines = 0;
    [myLabel sizeToFit];

Longer label text with sizeToFit


Longer Version

I'll make my label in code so that you can see what's going on. You can set up most of this in Interface Builder too. My setup is a View-Based App with a background image I made in Photoshop to show margins (20 points). The label is an attractive orange color so you can see what's going on with the dimensions.

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 20 point top and left margin. Sized to leave 20 pt at right.
    CGRect labelFrame = CGRectMake(20, 20, 280, 150);
    UILabel *myLabel = [[UILabel alloc] initWithFrame:labelFrame];
    [myLabel setBackgroundColor:[UIColor orangeColor]];

    NSString *labelText = @"I am the very model of a modern Major-General, I've information vegetable, animal, and mineral";
    [myLabel setText:labelText];

    // Tell the label to use an unlimited number of lines
    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

    [self.view addSubview:myLabel];
}

Some limitations of using sizeToFit come into play with center- or right-aligned text. Here's what happens:

    // myLabel.textAlignment = NSTextAlignmentRight;
    myLabel.textAlignment = NSTextAlignmentCenter;

    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

enter image description here

The label is still sized with a fixed top-left corner. You can save the original label's width in a variable and set it after sizeToFit, or give it a fixed width to counter these problems:

    myLabel.textAlignment = NSTextAlignmentCenter;

    [myLabel setNumberOfLines:0];
    [myLabel sizeToFit];

    CGRect myFrame = myLabel.frame;
    // Resize the frame's width to 280 (320 - margins)
    // width could also be myOriginalLabelFrame.size.width
    myFrame = CGRectMake(myFrame.origin.x, myFrame.origin.y, 280, myFrame.size.height);
    myLabel.frame = myFrame;

label alignment


Note that sizeToFit will respect your initial label's minimum width. If you start with a label 100 wide and call sizeToFit on it, it will give you back a (possibly very tall) label with 100 (or a little less) width. You might want to set your label to the minimum width you want before resizing.

Correct label alignment by resizing the frame width

Some other things to note:

Whether lineBreakMode is respected depends on how it's set. NSLineBreakByTruncatingTail (the default) is ignored after sizeToFit, as are the other two truncation modes (head and middle). NSLineBreakByClipping is also ignored. NSLineBreakByCharWrapping works as usual. The frame width is still narrowed to fit to the rightmost letter.


Mark Amery gave a fix for NIBs and Storyboards using Auto Layout in the comments:

If your label is included in a nib or storyboard as a subview of the view of a ViewController that uses autolayout, then putting your sizeToFit call into viewDidLoad won't work, because autolayout sizes and positions the subviews after viewDidLoad is called and will immediately undo the effects of your sizeToFit call. However, calling sizeToFit from within viewDidLayoutSubviews will work.


My Original Answer (for posterity/reference):

This uses the NSString method sizeWithFont:constrainedToSize:lineBreakMode: to calculate the frame height needed to fit a string, then sets the origin and width.

Resize the frame for the label using the text you want to insert. That way you can accommodate any number of lines.

CGSize maximumSize = CGSizeMake(300, 9999);
NSString *dateString = @"The date today is January 1st, 1999";
UIFont *dateFont = [UIFont fontWithName:@"Helvetica" size:14];
CGSize dateStringSize = [dateString sizeWithFont:dateFont 
        constrainedToSize:maximumSize 
        lineBreakMode:self.dateLabel.lineBreakMode];

CGRect dateFrame = CGRectMake(10, 10, 300, dateStringSize.height);

self.dateLabel.frame = dateFrame;
12
  • 12
    you need to remove autolayout
    – hungbm06
    Oct 22, 2014 at 5:18
  • 4
    Here's a simple way to solve the problem: stackoverflow.com/a/26632490/636559 Oct 29, 2014 at 14:10
  • 3
    This answer is unnecessarily complicated and it is using a "word around". Please see suggestion below of simply changing the vertical content hugging priority. Doesn't require any code...
    – beetree
    Jan 23, 2015 at 1:45
  • 1
    [myLabel sizeToFit] is no good in UITableViewCells, since labels here are reused and new texts may not fit. Feb 1, 2016 at 14:47
  • 2
    You still can use AutoLayout and constraints, but assure the [height] will not be fixed. For example: Set Left, Top and Right to equals 8px, but Bottom you can set "Greater Than or Equal" 8px. It'll say to iOS, let my sizeToFit decides the better height for my label. Jan 27, 2017 at 11:55
345
  1. Set the new text:

    myLabel.text = @"Some Text"
    
  2. Set the maximum number of lines to 0 (automatic):

    myLabel.numberOfLines = 0
    
  3. Set the frame of the label to the maximum size:

    myLabel.frame = CGRectMake(20,20,200,800)
    
  4. Call sizeToFit to reduce the frame size so the contents just fit:

    [myLabel sizeToFit]
    

The labels frame is now just high and wide enough to fit your text. The top left should be unchanged. I have tested this only with the top left-aligned text. For other alignments, you might have to modify the frame afterward.

Also, my label has word wrapping enabled.

4
  • This worked fine for me. I set the dimensions of my UILabel and changed numberOfLines to 0 in IB and then after setting the text called [myLabel sizeToFit].
    – Dan
    Jul 14, 2011 at 21:34
  • works perfectly for me, after setting the number of lines in Attr. Inspector
    – d2burke
    Mar 10, 2012 at 2:37
  • Does not work in case of number of lines more than 1
    – Tom
    Feb 12, 2014 at 15:58
  • It doesn't work when you want a label of two lines, but the text requires more lines. Feb 6, 2015 at 16:46
165

Just in case it's of any help to anyone, I had the same problem but was able to solve the issue simply by switching from using UILabel to using UITextView. I appreciate this isn't for everyone because the functionality is a bit different.

If you do switch to using UITextView, you can turn off all the Scroll View properties as well as User Interaction Enabled... This will force it to act more like a label.

enter image description here

7
  • 1
    Not sure how this will affect the performance if many UILabels are converted to text views.
    – ninjaneer
    Nov 10, 2013 at 12:17
  • 2
    All the other solutions on this thread didn't work for me in iOS 7 (for whatever reason). But simply using a UITextView gave me the desired result right away. Apr 29, 2014 at 0:05
  • 1
    It's a workaround, it still needs some adjustments to make it look authentic, but indeed this is the easiest none code solution that I saw, thumbs up. Sep 11, 2015 at 7:19
  • 1
    I like this solution. Granted, there may be performance issues and such, for a simple label on a relatively simple view, this was perfect for what I needed (and I can't notice any performance impacts)
    – JCutting8
    Jan 17, 2016 at 0:29
  • 2
    A small drawback of this method is that it will introduce extra intrinsic padding to the text. A quick fix is to introduce a negative constraint.
    – Sira Lam
    Feb 27, 2018 at 4:05
164

Refering to the extension solution:

for(int i=1; i< newLinesToPad; i++) 
    self.text = [self.text stringByAppendingString:@"\n"];

should be replaced by

for(int i=0; i<newLinesToPad; i++)
    self.text = [self.text stringByAppendingString:@"\n "];

Additional space is needed in every added newline, because iPhone UILabels' trailing carriage returns seems to be ignored :(

Similarly, alignBottom should be updated too with a @" \n@%" in place of "\n@%" (for cycle initialization must be replaced by "for(int i=0..." too).

The following extension works for me:

// -- file: UILabel+VerticalAlign.h
#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end

// -- file: UILabel+VerticalAlign.m
@implementation UILabel (VerticalAlign)
- (void)alignTop {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [self.text stringByAppendingString:@"\n "];
}

- (void)alignBottom {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
}
@end

Then call [yourLabel alignTop]; or [yourLabel alignBottom]; after each yourLabel text assignment.

10
  • @D.S. I noticed that you are adding VerticalAlign between parenthesis after @implementation UILabel. Being new to Objective-C I haven't ran across this syntax before. What is this called?
    – Julian
    May 12, 2011 at 16:05
  • Amazing, didn't know about categories, this gives me even more appreciation for the Objective-c language. Learning more languages is so important to become a good programmer. May 26, 2011 at 8:04
  • Gave an upvote. but iirc this won't work if you do not know the number of lines which is a downside
    – Tjirp
    Nov 30, 2011 at 10:02
  • I've to show 3 lines of text and align text to top. So, do I've to set number of lines to 3. When I set it to 3, i'm seeing "..." if the text is less (that fits in one line). How to avoid this "..."
    – Satyam
    Dec 10, 2011 at 16:41
  • 1
    I posted an edit of this category, hopefully it will be approved shortly. The methods sizeWithFont:constrainedToSize:lineBreakMode: and sizeWithFont: are both depreciated in iOS7. Also, this category only works on labels when numberOfLines is greater than 0. Apr 1, 2014 at 18:32
147

No muss, no fuss

@interface MFTopAlignedLabel : UILabel

@end


@implementation MFTopAlignedLabel

- (void)drawTextInRect:(CGRect) rect
{
    NSAttributedString *attributedText = [[NSAttributedString alloc]     initWithString:self.text attributes:@{NSFontAttributeName:self.font}];
    rect.size.height = [attributedText boundingRectWithSize:rect.size
                                            options:NSStringDrawingUsesLineFragmentOrigin
                                            context:nil].size.height;
    if (self.numberOfLines != 0) {
        rect.size.height = MIN(rect.size.height, self.numberOfLines * self.font.lineHeight);
    }
    [super drawTextInRect:rect];
}

@end

No muss, no Objective-c, no fuss but Swift 3:

class VerticalTopAlignLabel: UILabel {

    override func drawText(in rect:CGRect) {
        guard let labelText = text else {  return super.drawText(in: rect) }

        let attributedText = NSAttributedString(string: labelText, attributes: [NSFontAttributeName: font])
        var newRect = rect
        newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height

        if numberOfLines != 0 {
            newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
        }

        super.drawText(in: newRect)
    }

}

Swift 4.2

class VerticalTopAlignLabel: UILabel {

    override func drawText(in rect:CGRect) {
        guard let labelText = text else {  return super.drawText(in: rect) }

        let attributedText = NSAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font])
        var newRect = rect
        newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height

        if numberOfLines != 0 {
            newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
        }

        super.drawText(in: newRect)
    }

}
4
  • The swift version worked for me without any side effects! Great work!
    – l.vasilev
    Mar 14, 2017 at 11:55
  • 10
    Probably the best answer here, works in all scenarios. sizeToFit doesn't work if label is in UITableviewCell. Good work. Apr 3, 2018 at 11:36
  • 1
    Dear Apple, it shouldn't be this hard to get text to go upper left automatically. That said, great answer here @jasongregori . Tried hugging concept and the top answer and niether worked for a CollectionViewCell label. Custom class for UILabel is the solution.
    – John Pitts
    Aug 12, 2021 at 16:06
  • 1
    For those who don't know custom class concept, fix the above answer with the following recipe: 1. Create a new Swift file in your project. COMMAND + N. 2. Insert the code pictured below for a custom UILabel class. 3. DON'T FORGET TO IMPORT UIKit to this file otherwise you'll see red all over the place on this code, beginning with XCode not recognizing 'UILabel' as the class type. 4. Also don't forget to go into your label's Identity Inspector to toggle the Custom Class and find 'VerticalTopAlignLabel' or whatever YOU named it.
    – John Pitts
    Aug 12, 2021 at 16:16
104

Easiest approach using Storyboard:

Embed Label in a StackView and set the following two attributes of StackView in the Attribute Inspector:

1- Axis to Horizontal,

2- Alignment to Top

enter image description here

5
  • 2
    For better results you can do this StackView > View > UILabel, because when you just embed an UILabel inside a StackView, the StackView resize to fit UILabel to minimum size Aug 2, 2018 at 18:39
  • Great idea to place UILabel into some UIView subclass (plain UIView is usually enough) and let that label grow in down direction. Thanks! Sep 10, 2018 at 7:01
  • 1
    With the Editor->Embed menu command with your label selected, the labels constraints are cleared for you by Xcode, you can then just set the constraints for the StackView. This approach is closest to a 'SwiftUI' layout approach which is how I discovered it. Apr 6, 2020 at 8:30
  • 1
    You don't need the UIStackView, just embed the UILabel inside an UIView. Set the UIView constraints to occupy the maximum space the UILabel should grow to. Then set the UILabel to top, right, and left of the UIView and set a constraint also to bottom with distance >= 0. Sep 9, 2021 at 14:20
  • Solved my problem Dec 7, 2023 at 16:27
83

Like the answer above, but it wasn't quite right, or easy to slap into code so I cleaned it up a bit. Add this extension either to it's own .h and .m file or just paste right above the implementation you intend to use it:

#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end


@implementation UILabel (VerticalAlign)
- (void)alignTop
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=0; i<= newLinesToPad; i++)
    {
        self.text = [self.text stringByAppendingString:@" \n"];
    }
}

- (void)alignBottom
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=0; i< newLinesToPad; i++)
    {
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
    }
}
@end

And then to use, put your text into the label, and then call the appropriate method to align it:

[myLabel alignTop];

or

[myLabel alignBottom];
1
  • sizeWithFont deprecated
    – tdios
    Dec 18, 2019 at 21:08
72

An even quicker (and dirtier) way to accomplish this is by setting the UILabel's line break mode to "Clip" and adding a fixed amount of newlines.

myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];

This solution won't work for everyone -- in particular, if you still want to show "..." at the end of your string if it exceeds the number of lines you're showing, you'll need to use one of the longer bits of code -- but for a lot of cases this'll get you what you need.

2
  • 3
    Setting the line break mode to 'clip' seems to mess up the auto-sizing of the label. Use UILineBreakModeWordWrap instead. Mar 23, 2011 at 10:56
  • and better add spaces " \n \n "
    – djdance
    Jan 15, 2016 at 16:14
64

Instead of UILabel you may use UITextField which has vertical alignment option:

textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // Don't allow interaction
2
  • 7
    Caveat: UITextField only allows a single line of text. Dec 29, 2014 at 19:27
  • 3
    To complete @DavidJames comment : UITextView would be more appropriate Jul 26, 2017 at 10:13
55

I've struggled with this one for a long time and I wanted to share my solution.

This will give you a UILabel that will autoshrink text down to 0.5 scales and vertically center the text. These options are also available in Storyboard/IB.

[labelObject setMinimumScaleFactor:0.5];
[labelObject setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];
1
  • It worked as perfect among all the answers provided. Thanks @David Greco. Along with these properties, if we set adjustsFontSizeToFitWidth to YES then the text will fit into the frame without modifying the label's frame.
    – Ashok
    Mar 10, 2015 at 13:27
47

Create a new class

LabelTopAlign

.h file

#import <UIKit/UIKit.h>


@interface KwLabelTopAlign : UILabel {

}

@end

.m file

#import "KwLabelTopAlign.h"


@implementation KwLabelTopAlign

- (void)drawTextInRect:(CGRect)rect {
    int lineHeight = [@"IglL" sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, 9999.0f)].height;
    if(rect.size.height >= lineHeight) {
        int textHeight = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, rect.size.height)].height;
        int yMax = textHeight;
        if (self.numberOfLines > 0) {
            yMax = MIN(lineHeight*self.numberOfLines, yMax);    
        }

        [super drawTextInRect:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, yMax)];
    }
}

@end

Edit

Here's a simpler implementation that does the same:

#import "KwLabelTopAlign.h"

@implementation KwLabelTopAlign

- (void)drawTextInRect:(CGRect)rect
{
    CGFloat height = [self.text sizeWithFont:self.font
                            constrainedToSize:rect.size
                                lineBreakMode:self.lineBreakMode].height;
    if (self.numberOfLines != 0) {
        height = MIN(height, self.font.lineHeight * self.numberOfLines);
    }
    rect.size.height = MIN(rect.size.height, height);
    [super drawTextInRect:rect];
}

@end
1
  • +1 for the real answer. Unlike the sizeToFit solutions this actually makes the UILabel put any text at the top, even if you dynamically replace a shorter text with a longer one or vice versa.
    – SnakE
    Feb 11, 2013 at 23:00
42

enter image description here

In Interface Builder

  • Set UILabel to size of biggest possible Text
  • Set Lines to '0' in Attributes Inspector

In your code

  • Set the text of the label
  • Call sizeToFit on your label

Code Snippet:

self.myLabel.text = @"Short Title";
[self.myLabel sizeToFit];
1
  • worked great, except in my case I needed to set lines to 2 -- have a UILabel inside a UITableViewCell and setting to 0 made it overlap, but setting to 2 worked (cell has enough room for 2 lines)
    – eselk
    Oct 1, 2012 at 22:06
41

Use textRect(forBounds:limitedToNumberOfLines:).

class TopAlignedLabel: UILabel {
  override func drawText(in rect: CGRect) {
    let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
    super.drawText(in: textRect)
  }
}
6
  • 2
    You sir are a god! Oct 4, 2017 at 16:33
  • 5
    This answer should get way more upvotes as it is by far the nicest and cleanest solution! Jan 28, 2018 at 21:31
  • 1
    Thats nice. It lead me to the right direction to vertically center my label.
    – Leo Dabus
    Dec 28, 2020 at 5:26
  • 2
    Very elegant solution Aug 10, 2021 at 14:22
  • 1
    This works for me. This should be upvoted more. Aug 16, 2022 at 5:44
38

For Adaptive UI(iOS8 or after) , Vertical Alignment of UILabel is to be set from StoryBoard by Changing the properties noOfLines=0` and

Constraints

  1. Adjusting UILabel LefMargin, RightMargin and Top Margin Constraints.

  2. Change Content Compression Resistance Priority For Vertical=1000` So that Vertical>Horizontal .

Constraints of UILabel

Edited:

noOfLines=0

and the following constraints are enough to achieve the desired results.

enter image description here

1
  • This was awesome. Can you explain why the Vertical>Horizontal did the job? Thanks.
    – Gabriel
    Dec 1, 2016 at 16:55
37

What I did in my app was to set the UILabel's line property to 0 as well as to create a bottom constraint of the UILabel and make sure it is being set to >= 0 as shown in the image below. enter image description here

3
  • I have no idea why this isn't the accepted answer. So much simpler than the one that is. Nice answer!
    – AndroidDev
    Jun 12, 2020 at 21:20
  • Yes! This is what I was looking for. This should be the accepted answer. Mar 9, 2021 at 12:36
  • The superior answer by far. Thank you! +1
    – Brittany
    Jul 27, 2021 at 15:06
35

Create a subclass of UILabel. Works like a charm:

// TopLeftLabel.h

#import <Foundation/Foundation.h>

@interface TopLeftLabel : UILabel 
{
}

@end

// TopLeftLabel.m

#import "TopLeftLabel.h"

@implementation TopLeftLabel

- (id)initWithFrame:(CGRect)frame 
{
    return [super initWithFrame:frame];
}

- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines 
{
    CGRect textRect = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];    
    textRect.origin.y = bounds.origin.y;
    return textRect;
}

-(void)drawTextInRect:(CGRect)requestedRect 
{
    CGRect actualRect = [self textRectForBounds:requestedRect limitedToNumberOfLines:self.numberOfLines];
    [super drawTextInRect:actualRect];
}

@end

As discussed here.

0
29

I wrote a util function to achieve this purpose. You can take a look:

// adjust the height of a multi-line label to make it align vertical with top
+ (void) alignLabelWithTop:(UILabel *)label {
  CGSize maxSize = CGSizeMake(label.frame.size.width, 999);
  label.adjustsFontSizeToFitWidth = NO;

  // get actual height
  CGSize actualSize = [label.text sizeWithFont:label.font constrainedToSize:maxSize lineBreakMode:label.lineBreakMode];
  CGRect rect = label.frame;
  rect.size.height = actualSize.height;
  label.frame = rect;
}

.How to use? (If lblHello is created by Interface builder, so I skip some UILabel attributes detail)

lblHello.text = @"Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!";
lblHello.numberOfLines = 5;
[Utils alignLabelWithTop:lblHello];

I also wrote it on my blog as an article: http://fstoke.me/blog/?p=2819

0
27

I took a while to read the code, as well as the code in the introduced page, and found that they all try to modify the frame size of label, so that the default center vertical alignment would not appear.

However, in some cases we do want the label to occupy all those spaces, even if the label does have so much text (e.g. multiple rows with equal height).

Here, I used an alternative way to solve it, by simply pad newlines to the end of label (pls note that I actually inherited the UILabel, but it is not necessary):

CGSize fontSize = [self.text sizeWithFont:self.font];

finalHeight = fontSize.height * self.numberOfLines;
finalWidth = size.width;    //expected width of label

CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];

int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

for(int i = 0; i < newLinesToPad; i++)
{
    self.text = [self.text stringByAppendingString:@"\n "];
}
20

I took the suggestions here and created a view which can wrap a UILabel and will size it and set the number of lines so that it is top aligned. Simply put a UILabel as a subview:

@interface TopAlignedLabelContainer : UIView
{
}

@end

@implementation TopAlignedLabelContainer

- (void)layoutSubviews
{
    CGRect bounds = self.bounds;

    for (UILabel *label in [self subviews])
    {
        if ([label isKindOfClass:[UILabel class]])
        {
            CGSize fontSize = [label.text sizeWithFont:label.font];

            CGSize textSize = [label.text sizeWithFont:label.font
                                     constrainedToSize:bounds.size
                                         lineBreakMode:label.lineBreakMode];

            label.numberOfLines = textSize.height / fontSize.height;

            label.frame = CGRectMake(0, 0, textSize.width,
                 fontSize.height * label.numberOfLines);
        }
    }
}

@end
20

You can use TTTAttributedLabel, it supports vertical alignment.

@property (nonatomic) TTTAttributedLabel* label;
<...>

//view's or viewController's init method
_label.verticalAlignment = TTTAttributedLabelVerticalAlignmentTop;
16

I've found the answers on this question are now a bit out-of-date, so adding this for the auto layout fans out there.

Auto layout makes this issue pretty trivial. Assuming we're adding the label to UIView *view, the following code will accomplish this:

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
[label setText:@"Some text here"];
[label setTranslatesAutoresizingMaskIntoConstraints:NO];
[view addSubview:label];

[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label]|" options:0 metrics:nil views:@{@"label": label}]];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label]" options:0 metrics:nil views:@{@"label": label}]];

The label's height will be calculated automatically (using it's intrinsicContentSize) and the label will be positioned edge-to-edge horizontally, at the top of the view.

0
14

I wanted to have a label which was able to have multi-lines, a minimum font size, and centred both horizontally and vertically in it's parent view. I added my label programmatically to my view:

- (void) customInit {
    // Setup label
    self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    self.label.numberOfLines = 0;
    self.label.lineBreakMode = UILineBreakModeWordWrap;
    self.label.textAlignment = UITextAlignmentCenter;

    // Add the label as a subview
    self.autoresizesSubviews = YES;
    [self addSubview:self.label];
}

And then when I wanted to change the text of my label...

- (void) updateDisplay:(NSString *)text {
    if (![text isEqualToString:self.label.text]) {
        // Calculate the font size to use (save to label's font)
        CGSize textConstrainedSize = CGSizeMake(self.frame.size.width, INT_MAX);
        self.label.font = [UIFont systemFontOfSize:TICKER_FONT_SIZE];
        CGSize textSize = [text sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
        while (textSize.height > self.frame.size.height && self.label.font.pointSize > TICKER_MINIMUM_FONT_SIZE) {
            self.label.font = [UIFont systemFontOfSize:self.label.font.pointSize-1];
            textSize = [ticker.blurb sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
        }
        // In cases where the frame is still too large (when we're exceeding minimum font size),
        // use the views size
        if (textSize.height > self.frame.size.height) {
            textSize = [text sizeWithFont:self.label.font constrainedToSize:self.frame.size];
        }

        // Draw 
        self.label.frame = CGRectMake(0, self.frame.size.height/2 - textSize.height/2, self.frame.size.width, textSize.height);
        self.label.text = text;
    }
    [self setNeedsDisplay];
}

Hope that helps someone!

14

FXLabel (on github) does this out of the box by setting label.contentMode to UIViewContentModeTop. This component is not made by me, but it is a component I use frequently and has tons of features, and seems to work well.

14

I've used a lot of the methods above, and just want to add a quick-and-dirty approach I've used:

myLabel.text = [NSString stringWithFormat:@"%@\n\n\n\n\n\n\n\n\n",@"My label text string"];

Make sure the number of newlines in the string will cause any text to fill the available vertical space, and set the UILabel to truncate any overflowing text.

Because sometimes good enough is good enough.

8
  • However given he variation in screen size heights of iOS devices, there would then need to be a variable number of '\n' to account for uilabel changing height (which is a possibility). Thus this method is not particularly useful long term.
    – Rambatino
    Sep 15, 2014 at 12:21
  • Note: "quick-and-dirty" not "perfect solution for all time." Just sayin'. Sep 15, 2014 at 23:00
  • 2
    @CodeRoadie Quick and dirty did the trick for me, I had a couple of layout issues with the real answer. I could do it the "right way", but thank you for saving me some time! Mar 27, 2015 at 21:01
  • @dGambit please note: "quick and dirty" Aug 16, 2015 at 22:38
  • 1
    Something I learned recently when dynamically loading views with UITextView is that it can call dlopen in order to support text input. This can cause major lag on the UI thread, so this approach is much more performant!
    – yano
    Nov 30, 2015 at 22:14
11

for anyone reading this because the text inside your label is not vertically centered, keep in mind that some font types are not designed equally. for example, if you create a label with zapfino size 16, you will see the text is not perfectly centered vertically.

however, working with helvetica will vertically center your text.

1
  • Many custom fonts are not vertical centre aligned. UILabel or UITextView are always vertical centre aligned. No need to think about vertical alignment in iOS programming.
    – Amit Singh
    May 6, 2013 at 11:20
10

Subclass UILabel and constrain the drawing rectangle, like this:

- (void)drawTextInRect:(CGRect)rect
{
    CGSize sizeThatFits = [self sizeThatFits:rect.size];
    rect.size.height = MIN(rect.size.height, sizeThatFits.height);

    [super drawTextInRect:rect];
}

I tried the solution involving newline padding and ran into incorrect behavior in some cases. In my experience, it's easier to constrain the drawing rect as above than mess with numberOfLines.

P.S. You can imagine easily supporting UIViewContentMode this way:

- (void)drawTextInRect:(CGRect)rect
{
    CGSize sizeThatFits = [self sizeThatFits:rect.size];

    if (self.contentMode == UIViewContentModeTop) {
        rect.size.height = MIN(rect.size.height, sizeThatFits.height);
    }
    else if (self.contentMode == UIViewContentModeBottom) {
        rect.origin.y = MAX(0, rect.size.height - sizeThatFits.height);
        rect.size.height = MIN(rect.size.height, sizeThatFits.height);
    }

    [super drawTextInRect:rect];
}
10

If you are using autolayout, set the vertical contentHuggingPriority to 1000, either in code or IB. In IB you may then have to remove a height constraint by setting it's priority to 1 and then deleting it.

0
9

Swift 5

Here is rendering text starting from the top-left corner, and keeping possible adjusted text size.

final class TopAlignedLabel: UILabel {
  override func drawText(in rect: CGRect) {
    super.drawText(in: .init(
      origin: .zero, 
      size: textRect(
        forBounds: rect, 
        limitedToNumberOfLines: numberOfLines
      ).size
    ))
  }
}
8

As long as you are not doing any complex task, you can use UITextView instead of UILabels.

Disable the scroll.

If you want the text to be displayed completely just user sizeToFit and sizeThatFits: methods

0
8

In swift,

let myLabel : UILabel!

To make your text of your Label to fit to screen and it's on the top

myLabel.sizeToFit()

To make your font of label to fit to the width of screen or specific width size.

myLabel.adjustsFontSizeToFitWidth = YES

and some textAlignment for label :

myLabel.textAlignment = .center

myLabel.textAlignment = .left

myLabel.textAlignment = .right

myLabel.textAlignment = .Natural

myLabel.textAlignment = .Justified

1
  • Just a change of syntax from the old syntax of [myLabel sizeToFit]. Thank you!
    – velkoon
    Oct 6, 2018 at 0:26

Not the answer you're looking for? Browse other questions tagged or ask your own question.