Vertically align UILabel
Solution 1
I'm the author of FXLabel, and whilst I don't know Manish, I believe he was trying to help (if he was advertising for me, I certainly didn't ask him to, and I'm not paying him - sorry Manish!).
One of FXLabel's features is that it respects the UIContentMode property of the label, as set in Interface builder. This means you can set label.contentMode = UIViewContentModeTop; to align the text to the top of the label view (which doesn't work for a regular UILabel). The relevant example is here:
https://github.com/nicklockwood/FXLabel/tree/master/Examples/Text%20Alignment
FXLabel is a drop-in subclass of UILabel, so I think it's a pretty good solution for the question being posed. However if the poster would rather solve the problem without using a 3rd party library (which is understandable) then here is the code to do it:
CGRect labelFrame = CGRectMake(22, 50, 280, 150);
UILabel *myLabel = [[UILabel alloc] initWithFrame:labelFrame];
[myLabel setText:finalRecipe];
[myLabel setBackgroundColor: [UIColor lightGrayColor]];
[myLabel setNumberOfLines:0];
CGFloat fontSize = 0.0f;
labelFrame.size = [myLabel.text sizeWithFont:myLabel.font
minFontSize:myLabel.minimumFontSize
actualFontSize:&fontSize
forWidth:labelFrame.width
lineBreakMode:myLabel.lineBreakMode];
myLabel.frame = labelFrame;
[self.view addSubview:myLabel];
Note:(This is untested, so apologies if there are any typos)
Solution 2
dont use UILabel
for this. Use UIButton
with UserInteractionEnabled = NO;
and that has options to vertical or horizontal align text inside it.
Here you go:
Swift:
btnDetail.titleLabel?.numberOfLines = 5
btnDetail.titleLabel?.lineBreakMode = .byCharWrapping
btnDetail.contentVerticalAlignment = .top
btnDetail.contentHorizontalAlignment = .left
btnDetail.isUserInteractionEnabled = false
btnDetail.autoresizesSubviews = true
btnDetail.autoresizingMask = .flexibleWidth
Obj-C
[btnDetail.titleLabel setNumberOfLines:5];
[btnDetail.titleLabel setLineBreakMode:NSLineBreakByCharWrapping];
[btnDetail setContentVerticalAlignment:UIControlContentVerticalAlignmentTop];
[btnDetail setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[btnDetail setUserInteractionEnabled:NO];
btnDetail.autoresizesSubviews = YES;
btnDetail.autoresizingMask = UIViewAutoresizingFlexibleWidth;
Solution 3
You'll need to subclass UILabel. Try this:
- (void)drawTextInRect:(CGRect)rect
{
CGSize sizeThatFits = [self sizeThatFits:rect.size];
rect.size.height = MIN(rect.size.height, sizeThatFits.height);
[super drawTextInRect:rect];
}
As you've discovered, UILabel vertically centers text within its bounds. Here we ask -sizeThatFits
for the text block size and uses it to constrain the drawing rectangle passed to UILabel, so that text is drawn from the top of the label bounds.
You could even support the ignored (sigh) contentMode
property like this:
- (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];
}
There's a bunch of other solutions and discussion here: Vertically align text to top within a UILabel
Solution 4
In Swift, JRC’s solution of subclassing UILabel
, overriding drawTextInRect
and conforming to UIViewContentMode
would look like this:
class AlignableUILabel: UILabel {
override func drawText(in rect: CGRect) {
var newRect = CGRect(x: rect.origin.x,y: rect.origin.y,width: rect.width, height: rect.height)
let fittingSize = sizeThatFits(rect.size)
if contentMode == UIViewContentMode.top {
newRect.size.height = min(newRect.size.height, fittingSize.height)
} else if contentMode == UIViewContentMode.bottom {
newRect.origin.y = max(0, newRect.size.height - fittingSize.height)
}
super.drawText(in: newRect)
}
}
Implementing is simply a matter of:
yourLabel.contentMode = UIViewContentMode.top
For me, it worked like a charm.
Solution 5
You can make it with a constraint on the interface builder.
- Put the number of lines that you want
- Create a constraint with an height enough bigger for 3 lines and in relation section put "Less Than or Equal".
Hope this help you !
Ashish Agarwal
Updated on July 09, 2022Comments
-
Ashish Agarwal almost 2 years
I am trying to vertically align the text in the UILabel view of my app. The problem is that I want the text to be vertically aligned to the top and the size of the label to be 280 x 150. I am only able to achieve one of these 2 things. If I remove the line
[myLabel sizeToFit];
then the alignment of the text is alright but the size is messed up. But if I add the above line, then the alignment is messed up but the size is alright. How do I fix this problem.
I've added the code below -
CGRect labelFrame = CGRectMake(22, 50, 280, 150); UILabel *myLabel = [[UILabel alloc] initWithFrame:labelFrame]; [myLabel setText:finalRecipe]; [myLabel setBackgroundColor: [UIColor lightGrayColor]]; [myLabel setNumberOfLines:0]; [myLabel sizeToFit]; [self.view addSubview:myLabel];