How to align UILabel text from bottom?
Asked Answered
M

13

47

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.

Mccarron answered 15/8, 2013 at 7:15 Comment(0)
A
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};
Arawn answered 15/8, 2013 at 7:24 Comment(6)
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?Mccarron
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 :)Arawn
Ya second is best.I will try and let u know.Mccarron
I tried,it seems working.But the problem is, how to enable multi-line for UITextField?Mccarron
Hi I implemented the same concept in UITextView. Its working perfectly. Thanks.. I have updated your answer which I implemented in my code.Mccarron
Hi can u edit your answer, So it will be suits best for my question.Currently its incomplete.Mccarron
G
28

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
Guttle answered 21/5, 2018 at 13:30 Comment(5)
Worth noting that this works seamlessly with a custom-classed UILabel in IB (set contentMode there) and also that sizeToFit() is not required with this solution.Solfa
This answer is great 👌Principled
how can you get interface builder to update the position of the displayed label? is that not possible?Bagger
@JamesJoshuaStreet you can try to add (at)IBDesignable on the line before the class initialization. Replace (at) with @. More info here: nshipster.com/ibinspectable-ibdesignable/#ibdesignableGuttle
hmm, yeah I had that but it wasn't working. Maybe I edited something important. I'll test it again mondayBagger
A
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};
Arawn answered 15/8, 2013 at 7:24 Comment(6)
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?Mccarron
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 :)Arawn
Ya second is best.I will try and let u know.Mccarron
I tried,it seems working.But the problem is, how to enable multi-line for UITextField?Mccarron
Hi I implemented the same concept in UITextView. Its working perfectly. Thanks.. I have updated your answer which I implemented in my code.Mccarron
Hi can u edit your answer, So it will be suits best for my question.Currently its incomplete.Mccarron
M
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
Mastoiditis answered 15/8, 2013 at 7:15 Comment(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.Naseberry
O
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.

Outstay answered 29/8, 2016 at 8:56 Comment(0)
P
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.

Pantelegraph answered 3/10, 2020 at 12:49 Comment(0)
S
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

Salot answered 2/3, 2021 at 22:37 Comment(0)
A
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
Alexio answered 28/2, 2023 at 19:50 Comment(0)
P
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];
Pecuniary answered 8/7, 2014 at 12:39 Comment(0)
A
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);
Ashly answered 7/8, 2014 at 22:11 Comment(0)
A
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

Antidote answered 27/11, 2019 at 3:42 Comment(0)
O
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)
  }
}
Otiose answered 24/6, 2023 at 19:10 Comment(0)
P
-2

You can subclass UILabel and overriding the method :

- (void)drawTextInRect:(CGRect)rect

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

Pantywaist answered 15/8, 2013 at 7:28 Comment(1)
You can also use - (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines; which may be more explicit.Mastoiditis
A
-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
Aletheaalethia answered 3/1, 2021 at 1:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.