Align text vertically inside a UILabel (Note: using AutoLayout)

I copy the same question asked before Question . I tried these solutions and could not solve it, since sizetofit was not effective when I use Autolayout.

first screenshot

The expected display is as follows.

second screenshot

+59
ios objective-c cocoa-touch uilabel autolayout
Feb 19 '15 at 11:35
source share
16 answers

Edit

In my original answer, I used the label paragraph style. It turns out that for multi-line labels this actually prevents the label from being multi-line. As a result, I removed it from the calculation. Learn more about this on Github.

For those of you who are more comfortable using Open Source, definitely check out TTTAttributedLabel , where you can set the alignment of text labels to TTTAttributedLabelVerticalAlignmentTop




The trick is to subclass UILabel and override drawTextInRect . Then make sure that the text is drawn at the beginning of the label borders.

Here's a naive implementation that you can use right now:

Swift

 @IBDesignable class TopAlignedLabel: UILabel { override func drawTextInRect(rect: CGRect) { if let stringText = text { let stringTextAsNSString = stringText as NSString var labelStringSize = stringTextAsNSString.boundingRectWithSize(CGSizeMake(CGRectGetWidth(self.frame), CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil).size super.drawTextInRect(CGRectMake(0, 0, CGRectGetWidth(self.frame), ceil(labelStringSize.height))) } else { super.drawTextInRect(rect) } } override func prepareForInterfaceBuilder() { super.prepareForInterfaceBuilder() layer.borderWidth = 1 layer.borderColor = UIColor.blackColor().CGColor } } 

Swift 3

  @IBDesignable class TopAlignedLabel: UILabel { override func drawText(in rect: CGRect) { if let stringText = text { let stringTextAsNSString = stringText as NSString let labelStringSize = stringTextAsNSString.boundingRect(with: CGSize(width: self.frame.width,height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil).size super.drawText(in: CGRect(x:0,y: 0,width: self.frame.width, height:ceil(labelStringSize.height))) } else { super.drawText(in: rect) } } override func prepareForInterfaceBuilder() { super.prepareForInterfaceBuilder() layer.borderWidth = 1 layer.borderColor = UIColor.black.cgColor } } 

Objective-c

 IB_DESIGNABLE @interface TopAlignedLabel : UILabel @end @implementation TopAlignedLabel - (void)drawTextInRect:(CGRect)rect { if (self.text) { CGSize labelStringSize = [self.text boundingRectWithSize:CGSizeMake(CGRectGetWidth(self.frame), CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:self.font} context:nil].size; [super drawTextInRect:CGRectMake(0, 0, ceilf(CGRectGetWidth(self.frame)),ceilf(labelStringSize.height))]; } else { [super drawTextInRect:rect]; } } - (void)prepareForInterfaceBuilder { [super prepareForInterfaceBuilder]; self.layer.borderWidth = 1; self.layer.borderColor = [UIColor blackColor].CGColor; } @end 



Since I used IBDesignable, you can add this shortcut to the storyboard and see how it happens, this is what seems to me.

enter image description here

+125
Feb 24 '15 at 13:55
source share

If you are not limited to having a fixed size UILabel, instead of justifying the text inside the UILabel, simply use the β‰₯ constraint on this label to resize it.

enter image description here

This is the most elegant solution using Auto Layout. However, be sure to set numOfLines to zero.

+37
Dec 07 '15 at 9:14
source share

You can use UITextView instead of UILabel:
Uncheck "Scrolling enabled"
Uncheck "Editable"
Uncheck "Select"
Set the background color to ClearColor

+31
Mar 01 '15 at 8:01
source share

I had the same problem and solved it. I just edited the base level in the Attribute Inspector section for the label. Set it to Align Centers.

Setting baseline to Align Centers

+7
Mar 18 '16 at 17:24
source share

Instead, I changed the lower space constant to priority @ 250 and solved my problem. And my label has a constant height with <= constant

+7
Jun 04 '16 at 15:37
source share

You would do this by removing the minimum height.

If you need a minimum height for something even below the label, you should use a container view that has resized based on the contents of the label, but the minimum has been used.

+4
Feb 19 '15 at 11:51
source share

The automatic layout only works with the edges / sizes of the controller, and not with the content.so controllers. It is not recommended to use the automatic layout to display the label text on top of the first line. according to me sizetofit is the best option for this.

+1
Feb 24 '15 at 13:16
source share

I used @Daniel Golasko's solution, and whenever the text inside the UILabel was longer than the UILabel could contain, the text will start to move down, rather than stay aligned up.

I changed this line to make sure the text is correctly aligned.

  [super drawTextInRect:CGRectMake(0, 0, ceilf(CGRectGetWidth(self.frame)),MIN(ceilf(labelStringSize.height), self.frame.size.height))]; 
+1
Jul 23 '15 at 17:44
source share

I had a similar problem in which there were 3 shortcuts. The middle label could have much longer text than the other two, so its height could become much larger.

Like this:

enter image description here

I set the lower space limit of the middle label as> = lower label.

enter image description here

This solved my problem.

+1
Aug 12 '16 at 9:40
source share

You can try if the button [button setContentVerticalAlignment:UIControlContentVerticalAlignmentTop];

Edit:

You can try this if you want to use only the label:

stack overflow

0
Feb 19 '15 at 12:43
source share

For me, I did not set a height limit, the text always grows from the top of the label. The restrictions for this label are above, left, right. By the way, my tag has fixed line numbers, so don't worry about the height.

0
Oct 28 '16 at 21:16
source share
  @IBInspectable var alignTop: Bool = false func setAlignTop() { let text = self.text! let lines = text.characters.split(separator: "\n").count if lines < self.numberOfLines { var newLines = "" for _ in 0..<(self.numberOfLines - lines) { newLines = newLines.appending("\n ") } self.text! = text.appending(newLines) } } override var text: String? { didSet { if alignTop { self.setAlignTop() } } } 
0
Dec 21 '16 at 3:01
source share

Daniel Galasko's Swift 3 solution improves here (here you can also set the maximum number of lines without shifting from the top):

 import UIKit @IBDesignable class TopAlignedLabel: UILabel { override func drawText(in rect: CGRect) { if let stringText = text { let stringTextAsNSString = stringText as NSString let labelString = stringTextAsNSString.boundingRect(with: CGSize(width: frame.width, height: .greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil) super.drawText(in: CGRect(x: 0, y: 0, width: frame.width, height: ceil(labelString.size.height) > frame.height ? frame.height : ceil(labelString.size.height))) } else { super.drawText(in: rect) } } override func prepareForInterfaceBuilder() { super.prepareForInterfaceBuilder() layer.borderWidth = 1 layer.borderColor = UIColor.black.cgColor } } 
0
Jul 22 '17 at 12:00
source share

There is a simple solution for cases where the height of the label does not have to be constant: put the Label in the Stack View . Remember to add start and end pointers to the Stack View . Here is a screenshot of how to do this in a storyboard:

enter image description here

0
Aug 24 '17 at 11:38 on
source share

use this class, you can change the alignment text using the contentMode .

Supported Case: .top, .bottom, .left, .right, .topLeft, .topRight, .bottomLeft, .bottomRight

Swift4

 import Foundation import UIKit @IBDesignable class UIAlignedLabel: UILabel { override func drawText(in rect: CGRect) { if let text = text as NSString? { func defaultRect(for maxSize: CGSize) -> CGRect { let size = text .boundingRect( with: maxSize, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [ NSAttributedStringKey.font: font ], context: nil ).size let rect = CGRect( origin: .zero, size: CGSize( width: min(frame.width, ceil(size.width)), height: min(frame.height, ceil(size.height)) ) ) return rect } switch contentMode { case .top, .bottom, .left, .right, .topLeft, .topRight, .bottomLeft, .bottomRight: let maxSize = CGSize(width: frame.width, height: frame.height) var rect = defaultRect(for: maxSize) switch contentMode { case .bottom, .bottomLeft, .bottomRight: rect.origin.y = frame.height - rect.height default: break } switch contentMode { case .right, .topRight, .bottomRight: rect.origin.x = frame.width - rect.width default: break } super.drawText(in: rect) default: super.drawText(in: rect) } } else { super.drawText(in: rect) } } } 
0
Nov 26 '18 at 12:57
source share

Swift 4

You must subclass UILabel and override the text display mapping.

 class UITopAlignedLabel: UILabel { override func drawText(in rect: CGRect) { guard let string = text else { super.drawText(in: rect) return } let size = (string as NSString).boundingRect( with: CGSize(width: rect.width, height: .greatestFiniteMagnitude), options: [.usesLineFragmentOrigin], attributes: [.font: font], context: nil).size var rect = rect rect.size.height = size.height.rounded() super.drawText(in: rect) } } 
0
Nov 30 '18 at 11:24
source share



All Articles