How to find UILabel's number of Lines
As pointed out, this post relates how to get the height, rather than the number of lines. To get the number of lines,
- Get the height for a single letter, e.g.
@"A"
. - Divide the height of the string by the height obtained in 1 above.
E.g.
CGFloat unitHeight = [@"A" heightForWidth:width usingFont:font];
CGFloat blockHeight = [text heightForWidth:width usingFont:font];
NSInteger numberOfLines = ceilf(blockHeight / unitHeight);
// need to #include <math.h> for ^^^^^
As of iOS 7, the way of getting a label's desired height changed. To get the height, you can use the following code:
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
CGSize labelSize = (CGSize){width, FLT_MAX};
CGRect r = [self boundingRectWithSize:labelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: font} context:context];
where the height is r.size.height
. Note that font
must be provided. You can put this into a category for NSString for convenience, e.g.
@implementation NSString (HeightCalc)
- (CGFloat)heightForWidth:(CGFloat)width usingFont:(UIFont *)font
{
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
CGSize labelSize = (CGSize){width, FLT_MAX};
CGRect r = [self boundingRectWithSize:labelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: font} context:context];
return r.size.height;
}
@end
(Do memory management if not using ARC, btw.)
For iOS 6 and below:
Let's say you have a UILabel *myLabel
and you want to find out the height of the label (with some tweaking, you can get the # of lines by dividing the height with some appropriate number which depends on the font size).
UILabel *myLabel;
CGSize labelSize = [myLabel.text sizeWithFont:myLabel.font
constrainedToSize:myLabel.frame.size
lineBreakMode:UILineBreakModeWordWrap];
CGFloat labelHeight = labelSize.height;
Hope that helps. If it doesn't work let me know and I'll dig further. Also, untested code, but worked from reference.
For a more complete example, here is code which I put in the viewDidLoad: method of a view controller:
[super viewDidLoad];
UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(50,50,200,350)];
myLabel.numberOfLines = 0;
myLabel.lineBreakMode = UILineBreakModeWordWrap;
myLabel.text = @"This is some text in a UILabel which is long enough to wrap around the lines in said UILabel. This is a test, this is only a test.";
[self.view addSubview:myLabel];
CGSize labelSize = [myLabel.text sizeWithFont:myLabel.font
constrainedToSize:myLabel.frame.size
lineBreakMode:UILineBreakModeWordWrap];
CGFloat labelHeight = labelSize.height;
NSLog(@"labelHeight = %f", labelHeight);
[myLabel release];
The output from the NSLog goes:
2010-11-15 18:25:27.817 so_labelheight[728:307] labelHeight = 126.000000
For iOS7 and above, the officially sanctioned way to count the number of lines is to use TextKit:
func numberOfLinesForString(string: String, size: CGSize, font: UIFont) -> Int {
let textStorage = NSTextStorage(string: string, attributes: [NSFontAttributeName: font])
let textContainer = NSTextContainer(size: size)
textContainer.lineBreakMode = .ByWordWrapping
textContainer.maximumNumberOfLines = 0
textContainer.lineFragmentPadding = 0
let layoutManager = NSLayoutManager()
layoutManager.textStorage = textStorage
layoutManager.addTextContainer(textContainer)
var numberOfLines = 0
var index = 0
var lineRange : NSRange = NSMakeRange(0, 0)
for (; index < layoutManager.numberOfGlyphs; numberOfLines++) {
layoutManager.lineFragmentRectForGlyphAtIndex(index, effectiveRange: &lineRange)
index = NSMaxRange(lineRange)
}
return numberOfLines
}
The method -sizeWithFont:constrainedToSize:lineBreakMode
is now deprecated. You will want to use the method -boundingRectWithSize:options:attributes:context:
now.
Here's an examples:
CGSize boundingRectSize = CGSizeMake(widthToConstrainTo, CGFLOAT_MAX);
NSDictionary *attributes = @{NSFontAttributeName : [UIFont fontWithName:fontName size:14]};
CGRect labelSize = [labelString boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
attributes:attributes
context:nil];
In the above example I know the width I want to constrain the label to but since I'm not sure of the height, I just max the height param out using CGFLOAT_MAX
. For the options
you need to use NSStringDrawingUsesLineFragmentOrigin
and NSStringDrawingUsesFontLeading
if you're trying to calculate the size a label that can be any number of lines.
If you're looking for this answer in Swift 2+/iOS 8, it would look like this:
func numberOfLinesInLabel(yourString: String, labelWidth: CGFloat, labelHeight: CGFloat, font: UIFont) -> Int {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.minimumLineHeight = labelHeight
paragraphStyle.maximumLineHeight = labelHeight
paragraphStyle.lineBreakMode = .ByWordWrapping
let attributes: [String: AnyObject] = [NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle]
let constrain = CGSizeMake(labelWidth, CGFloat(Float.infinity))
let size = yourString.sizeWithAttributes(attributes)
let stringWidth = size.width
let numberOfLines = ceil(Double(stringWidth/constrain.width))
return Int(numberOfLines)
}