45

How the UILabel can be aligned from bottom. Let say, my label can hold three line of text.If the input text is single line, then this line should come bottom of the label.Please refer the below image for better understanding. The orange area is the full frame of label.Currently it has one line and it is aligned center. So what I want is, it should always aligned bottom regardless of how many lines.

enter image description here

Please suggest your ideas.

Thank you.

NSUserDefault
  • 1,794
  • 1
  • 17
  • 38

13 Answers13

25

Swift 4.2 version using the contentMode property to set top and bottom:

class VerticalAlignedLabel: UILabel {
    
    override func drawText(in rect: CGRect) {
        var newRect = rect
        switch contentMode {
        case .top:
            newRect.size.height = sizeThatFits(rect.size).height
        case .bottom:
            let height = sizeThatFits(rect.size).height
            newRect.origin.y += rect.size.height - height
            newRect.size.height = height
        default:
            ()
        }
        
        super.drawText(in: newRect)
    }
}

Then setup your label like that:

let label = VerticalAlignedLabel()
label.contentMode = .bottom
Community
  • 1
  • 1
Dunbar
  • 401
  • 5
  • 9
23

Here are two ways of doing that...

1. First set numberOfLines to 0 and then use sizeToFit property of UILabel so your UILabel display with its contentSize.

yourLabel.numberOfLines = 0;

[yourLabel sizeToFit];

See more information from this link: Vertically align text within a UILabel

2. Another option is to take UITextField instead of UILabel and set userInteractionEnabled to NO like below...

[yourTextField setUserInteractionEnabled:NO];

and then set the contentVerticalAlignment property to bottom like below...

[yourTextField setContentVerticalAlignment:UIControlContentVerticalAlignmentBottom];

UPDATE

Also, with UITextField, we can't achieve multiple lines. So instead we can use UITextView and set its userInteractionEnabled to NO. Then, use the code below to make it bottom aligned.

CGFloat topCorrect = ([label bounds].size.height - [label contentSize].height);
topCorrect = (topCorrect <0.0 ? 0.0 : topCorrect);
label.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
Faysal Ahmed
  • 7,501
  • 5
  • 28
  • 50
Paras Joshi
  • 20,427
  • 11
  • 57
  • 70
  • 1
    I have already tried first solution. But its not working properly.Its always aligned in the top and left. But it should be aligned at bottom and centre always. But second solution seems to be working. what about multiple line in second solution? will it be possible? – NSUserDefault Aug 15 '13 at 07:34
  • suppose this frame with 3 line is `CGRectMake(10,100,100,300);` then if you get one line only then set frame like that `CGRectMake(10,260,100,300);` , here just set some custom code with logic **otherwise** second option is best :) – Paras Joshi Aug 15 '13 at 07:36
  • Ya second is best.I will try and let u know. – NSUserDefault Aug 15 '13 at 07:39
  • I tried,it seems working.But the problem is, how to enable multi-line for UITextField? – NSUserDefault Aug 15 '13 at 07:53
  • 1
    Hi I implemented the same concept in UITextView. Its working perfectly. Thanks.. I have updated your answer which I implemented in my code. – NSUserDefault Aug 15 '13 at 08:17
  • 1
    Hi can u edit your answer, So it will be suits best for my question.Currently its incomplete. – NSUserDefault Aug 15 '13 at 09:09
20

Subclass UILabel

@interface Label : UILabel

@end

Then override drawTextInRect like so

@implementation Label

- (void)drawTextInRect:(CGRect)rect
{
    if(alignment == top) {

        rect.size.height = [self sizeThatFits:rect.size].height;
    }

    if(alignment == bottom) {

        CGFloat height = [self sizeThatFits:rect.size].height;

        rect.origin.y += rect.size.height - height;
        rect.size.height = height;
    }

    [super drawTextInRect:rect];
}

@end
Dustin
  • 1,030
  • 11
  • 15
  • 1
    This actually works perfectly for me, with almost no effort, and it doesn't feel hacky like some of the other solutions on here. – Matt Mc Feb 16 '15 at 06:06
3

i only set a bottom constraint to the super view in IB which works for me without using code and also number of Lines for a maximum constraint.

Tobe
  • 508
  • 5
  • 14
2

I recently ran into this problem and was able to solve it by putting my label in a stackview by itself. I got the idea from this post which had the same question but with multiple labels. The same technique can be used with a single label.

The stackview would have axis = horizontal and alignment = bottom (which is what does the trick).

My label is now perfectly aligned towards the bottom which is what I needed.

Phantom59
  • 947
  • 1
  • 8
  • 19
1

Put your UILabel in a vertical UIStackView with a dummy view as a spacer. Also, set the dummy view with a lower hugging and compression priority.

Top to Bottom:

  • Label
  • Dummy View

Bottom to Top:

  • Dummy View
  • Label

Screenshot

wizard_of_oz
  • 101
  • 1
  • 2
1

Swift 5 version of @Dustin code:

Subclass:

class VerticallyAlignedUILabel: UILabel {
    
    enum Alignment {
        case top
        case bottom
    }
    
    var alignment: Alignment = .top
    
    override func drawText(in rect: CGRect) {
        var rect = rect
        if alignment == .top {
            rect.size.height = sizeThatFits(rect.size).height
        } else if alignment == .bottom {
            let height = sizeThatFits(rect.size).height
            rect.origin.y += rect.size.height - height
            rect.size.height = height
        }
        super.drawText(in: rect)
    }
}

Usage:

let myLabel = VerticallyAlignedUILabel()
myLabel.text = "vertically aligned text"
myLabel.alignment = .bottom
Paul Bénéteau
  • 775
  • 2
  • 12
  • 36
0

I had the same issue. Here is how I made to align the text to the bottom of my UILabel:

- (void)alignLabel:(UILabel *)l withText:(NSString *)text verticalAlignOption:(int)vertAlign{
CGSize stringSize = [text sizeWithFont:l.font constrainedToSize:l.frame.size lineBreakMode:l.lineBreakMode];

switch (vertAlign) {
    case 0: // align = top
        l.frame = CGRectMake(l.frame.origin.x,
                                   l.frame.origin.y,
                                   l.frame.size.width,
                                   stringSize.height
                                   );
        break;
    case 1: // align = bottom
        l.frame = CGRectMake(l.frame.origin.x,
                                   (l.frame.origin.y + l.frame.size.height) - stringSize.height,
                                   l.frame.size.width,
                                   stringSize.height
                                   );
        break;
    case 2: // align = middle
        // default
        break;
}

l.text = text;
}

Ahd you simple call the method like this to align to the bottom:

[self alignLabel:self.mediaTitle withText:@"My text to align" verticalAlignOption:1];
barrast
  • 1,791
  • 1
  • 16
  • 27
0

Another option: use one label for your background color, I call this one originalLabel, and another for the text, called textLabel in my example. Then calculate the height and Y coordinate for textLabel:

[textLabel sizeToFit];
int height = textLabel.frame.size.height;
int yCoord = originalLabel.frame.origin.y + 
          originalLabel.frame.size.height - height;
textLabel.frame = CGRectMake( originalLabel.frame.origin.x, yCoord,
          textLabel.frame.size.width, height);
autremoi
  • 261
  • 2
  • 7
0

In IB as @Tobe said Bottom constraint to superview should work, Incase if you have multiple subview or horizontal stack view with one element to have bottom constraint then use Layout Margin to be Fixed with bottom less than other margins enter image description here

dasunse
  • 2,839
  • 1
  • 14
  • 32
0
class VerticalAlignedLabel: UILabel {
  
  let bottomSpacing: CGFloat = 10.0
  
  override func drawText(in rect: CGRect) {
    var newRect = rect
    let height = sizeThatFits(rect.size).height
    
    newRect.origin.y = rect.origin.y + rect.size.height - height - bottomSpacing
    newRect.size.height = height
    
    super.drawText(in: newRect)
  }
}
Mihail Salari
  • 1,471
  • 16
  • 17
-2

You can subclass UILabel and overriding the method :

- (void)drawTextInRect:(CGRect)rect

call super drawTextInRect with the rect where you want to use.

HiDeoo
  • 10,353
  • 8
  • 47
  • 47
ahmedalkaff
  • 313
  • 1
  • 3
  • You can also use - (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines; which may be more explicit. – Dustin Apr 03 '14 at 21:45
-2
  1. use autoLayout)
textLabel.numberOfLines = 0
textLabel.textAlignment = .center

textLabel.topAnchor.constraint(greaterThanOrEqualTo: sView.topAnchor).isActive = true
textLabel.leadingAnchor.constraint(equalTo: sView.leadingAnchor).isActive = true
textLabel.trailingAnchor.constraint(equalTo: sView.trailingAnchor).isActive = true
textLabel.bottomAnchor.constraint(equalTo: sView.bottomAnchor).isActive = true
Rus
  • 1
  • 1