如何dynamic计算UILabel高度?

我想根据给定的文本dynamic地计算UILabel的行数和高度。

尝试这个

// UILabel *myLabel; CGSize labelSize = [myLabel.text sizeWithFont:myLabel.font constrainedToSize:myLabel.frame.size lineBreakMode:NSLineBreakByWordWrapping]; CGFloat labelHeight = labelSize.height; int lines = [myLabel.text sizeWithFont:myLabel.font constrainedToSize:myLabel.frame.size lineBreakMode:NSLineBreakByWordWrapping].height/16; // '16' is font size 

要么

 int lines = labelHeight/16; NSLog(@"lines count : %i \n\n",lines); 

要么

 int lines = [myLabel.text sizeWithFont:myLabel.font constrainedToSize:myLabel.frame.size lineBreakMode:UILineBreakModeWordWrap].height /myLabel.font.pointSize; //fetching font size from font 

通过使用类别,只需创build名为的类别类

的UILabel + UILabelDynamicHeight.h

的UILabel + UILabelDynamicHeight.m

高度计算没有更多的紧张感。 请查看下面的实现。

iOS7及以上版本,iOS 7以下的更新:dynamic计算UILabel高度

 #define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) #define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) #define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) #define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) #define iOS7_0 @"7.0" 

的UILabel + UILabelDynamicHeight.h

 #import <UIKit/UIKit.h> @interface UILabel (UILabelDynamicHeight) #pragma mark - Calculate the size the Multi line Label /*====================================================================*/ /* Calculate the size of the Multi line Label */ /*====================================================================*/ /** * Returns the size of the Label * * @param aLabel To be used to calculte the height * * @return size of the Label */ -(CGSize)sizeOfMultiLineLabel; @end 

的UILabel + UILabelDynamicHeight.m

 #import "UILabel+UILabelDynamicHeight.h" @implementation UILabel (UILabelDynamicHeight) #pragma mark - Calculate the size,bounds,frame of the Multi line Label /*====================================================================*/ /* Calculate the size,bounds,frame of the Multi line Label */ /*====================================================================*/ /** * Returns the size of the Label * * @param aLabel To be used to calculte the height * * @return size of the Label */ -(CGSize)sizeOfMultiLineLabel{ //Label text NSString *aLabelTextString = [self text]; //Label font UIFont *aLabelFont = [self font]; //Width of the Label CGFloat aLabelSizeWidth = self.frame.size.width; if (SYSTEM_VERSION_LESS_THAN(iOS7_0)) { //version < 7.0 return [aLabelTextString sizeWithFont:aLabelFont constrainedToSize:CGSizeMake(aLabelSizeWidth, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping]; } else if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(iOS7_0)) { //version >= 7.0 //Return the calculated size of the Label return [aLabelTextString boundingRectWithSize:CGSizeMake(aLabelSizeWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{ NSFontAttributeName : aLabelFont } context:nil].size; } return [self bounds].size; } @end 

在UILabel实例上调用-sizeToFit会自动调整它的大小以适应它显示的文本,不需要计算。 如果你需要这个尺寸,你可以从标签的框架属性中获取。

 label.numberOfLines = 0; // allows label to have as many lines as needed label.text = @"some long text"; [label sizeToFit]; NSLog(@"Label's frame is: %@", NSStringFromCGRect(label.frame)); 

总而言之,您可以使用string并调用boundingRectWithSize来计算标签的高度。 您必须提供font作为一个属性,并包括.usesLineFragmentOrigin多行标签。

 let labelWidth = label.frame.width let maxLabelSize = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude) let actualLabelSize = label.text!.boundingRect(with: maxLabelSize, options: [.usesLineFragmentOrigin], attributes: [NSFontAttributeName: label.font], context: nil) let labelHeight = actualLabelSize.height 

一些扩展来做到这一点:

Swift版本:

 extension UILabel { func textHeight(for width: CGFloat) -> CGFloat { guard let text = text else { return 0 } return text.height(for: width, font: font) } func attributedTextHeight(for width: CGFloat) -> CGFloat { guard let attributedText = attributedText else { return 0 } return attributedText.height(for: width) } } extension String { func height(for width: CGFloat, font: UIFont) -> CGFloat { let maxSize = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude) let actualSize = self.boundingRect(for: maxSize, options: [.usesLineFragmentOrigin], attributes: [NSFontAttributeName: font], context: nil) return actualSize.height } } extension NSAttributedString { func height(for width: CGFloat) -> CGFloat { let maxSize = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude) let actualSize = boundingRect(for: maxSize, options: [.usesLineFragmentOrigin], context: nil) return actualSize.height } } 

Objective-C版本:

的UILabel + Utility.h

 #import <UIKit/UIKit.h> @interface UILabel (Utility) - (CGFloat)textHeightForWidth:(CGFloat)width; - (CGFloat)attributedTextHeightForWidth:(CGFloat)width; @end 

的UILabel + Utility.m

 @implementation NSString (Utility) - (CGFloat)heightForWidth:(CGFloat)width font:(UIFont *)font { CGSize maxSize = CGSizeMake(width, CGFLOAT_MAX); CGSize actualSize = [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : font} context:nil].size; return actualSize.height; } @end @implementation NSAttributedString (Utility) - (CGFloat)heightForWidth:(CGFloat)width { CGSize maxSize = CGSizeMake(width, CGFLOAT_MAX); CGSize actualSize = [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size; return actualSize.height; } @end @implementation UILabel (Utility) - (CGFloat)textHeightForWidth:(CGFloat)width { return [self.text heightForWidth:width font:self.font]; } - (CGFloat)attributedTextHeightForWidth:(CGFloat)width { return [self.attributedText heightForWidth:width]; } @end 

目前的解决scheme从iOS 7开始已被弃用。

这是一个更新的解决scheme:

 + (CGFloat)heightOfCellWithIngredientLine:(NSString *)ingredientLine withSuperviewWidth:(CGFloat)superviewWidth { CGFloat labelWidth = superviewWidth - 30.0f; // use the known label width with a maximum height of 100 points CGSize labelContraints = CGSizeMake(labelWidth, 100.0f); NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init]; CGRect labelRect = [ingredientLine boundingRectWithSize:labelContraints options:NSStringDrawingUsesLineFragmentOrigin attributes:nil context:context]; // return the calculated required height of the cell considering the label return labelRect.size.height; } 

我的解决scheme是这样设置的原因是因为我正在使用一个UITableViewCell并相对于标签占用多less空间dynamic调整单元格的大小。

在不调用sizeToFit的情况下,您可以通过一个非常简单的即插即用解决scheme来完成数字化操作:

 + (CGFloat)heightForText:(NSString*)text font:(UIFont*)font withinWidth:(CGFloat)width { CGSize size = [text sizeWithAttributes:@{NSFontAttributeName:font}]; CGFloat area = size.height * size.width; CGFloat height = roundf(area / width); return ceilf(height / font.lineHeight) * font.lineHeight; } 

我使用它有很多dynamic分配高度的UITableViewCells。

解决属性问题以及@Salman Zaidi。

 CGSize maxSize = CGSizeMake(lbl.frame.size.width, CGFLOAT_MAX); CGSize requiredSize = [lbl sizeThatFits:maxSize]; CGFloat height=requiredSize.height 

复制并粘贴此方法并使用它就像:

 [lblText setFrame:CGRectMake(lblText.frame.origin.x, lblText.frame.origin.y, width, [self getLabelHeight:lblText])]; - (CGFloat)getLabelHeight:(UILabel*)label { CGSize constraint = CGSizeMake(label.frame.size.width, CGFLOAT_MAX); CGSize size; NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init]; CGSize boundingBox = [label.text boundingRectWithSize:constraint options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:label.font} context:context].size; size = CGSizeMake(ceil(boundingBox.width), ceil(boundingBox.height)); return size.height; } 

在我的情况下,我为每个部分使用一个固定大小的标题 ,但在每个标题中有一个dynamic单元大小 。 单元格的高度取决于标签的高度。

使用:

 tableView.estimatedRowHeight = SomeNumber tableView.rowHeight = UITableViewAutomaticDimension 

工作, 使用时:

 tableView.reloadSections(IndexSet(integer: sender.tag) , with: .automatic) 

当大量的头文件没有被折叠的时候,甚至在使用types为.none (FYI,一个固定的头文件)时,创build了许多错误,例如头重复(相同types下的头文件typesx)和奇怪的animation身高和细胞高度的作品)。

解决scheme是使用heightForRowAtcallback,并计算标签的高度由你自己(加上animation看起来好多了 )。 请记住,高度被称为第一

 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let object = dataDetailsController.getRowObject(forIndexPath: indexPath) let label = UILabel(frame: tableView.frame) let font = UIFont(name: "HelveticaNeue-Bold", size: 25) label.text = object?.name label.font = font label.numberOfLines = 0 label.textAlignment = .center label.sizeToFit() let size = label.frame.height return Float(size) == 0 ? 34 : size } 

这是我用来计算多行UILabel高度的扩展,它是从以前的堆栈溢出后调整的片段:

 extension UILabel { func estimatedHeight(forWidth: CGFloat, text: String, ofSize: CGFloat) -> CGFloat { let size = CGSize(width: forWidth, height: CGFloat(MAXFLOAT)) let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin) let attributes = [NSFontAttributeName: UIFont.systemFont(ofSize: ofSize)] let rectangleHeight = String(text).boundingRect(with: size, options: options, attributes: attributes, context: nil).height return ceil(rectangleHeight) } } 

您需要创build一个string的扩展名并调用此方法

func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat { let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude) let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil) return ceil(boundingBox.height) }

您必须发送标签的宽度

如果你想标签采取dynamic行,你可以使用这个

 label.numberOfLines = 0; // allows label to have as many lines as needed label.text = @"some long text "; [label sizeToFit]; NSLog(@"Label's frame is: %@", NSStringFromCGRect(label.frame));