如何动态计算UILabel高度?

时间:2011-08-24 10:32:44

标签: iphone ios label uilabel

我想从同一文本的给定文本中动态计算UILabel的行数和高度。

14 个答案:

答案 0 :(得分:81)

试试这个

// 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

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

的类别类

<强>的UILabel + UILabelDynamicHeight.h

<强>的UILabel + UILabelDynamicHeight.m

高度计算不再紧张。请查看以下实施。

iOS7及更新版的更新以上,iOS 7以下:动态计算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

答案 1 :(得分:51)

在UILabel实例上调用-sizeToFit将自动调整其大小以适合它显示的文本,无需计算。如果你需要这个尺寸,你可以在之后从label的frame属性中获取它。

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));

答案 2 :(得分:30)

总而言之,您可以使用字符串并调用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: [.font: label.font], context: nil)
let labelHeight = actualLabelSize.height(withWidth:labelWidth)

要做的一些扩展:

Swift版本:

extension UILabel {
    func textHeight(withWidth width: CGFloat) -> CGFloat {
        guard let text = text else {
            return 0
        }
        return text.height(withWidth: width, font: font)
    }

    func attributedTextHeight(withWidth width: CGFloat) -> CGFloat {
        guard let attributedText = attributedText else {
            return 0
        }
        return attributedText.height(withWidth: width)
    }
}

extension String {
    func height(withWidth width: CGFloat, font: UIFont) -> CGFloat {
        let maxSize = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
        let actualSize = self.boundingRect(with: maxSize, options: [.usesLineFragmentOrigin], attributes: [.font : font], context: nil)
        return actualSize.height
    }
}

extension NSAttributedString {
    func height(withWidth width: CGFloat) -> CGFloat {
        let maxSize = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
        let actualSize = boundingRect(with: 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

答案 3 :(得分:17)

从iOS 7开始,目前的解决方案已被弃用。

这是一个更新的解决方案:

+ (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;
}

我的解决方案设置的原因是因为我正在使用UITableViewCell并相对于标签将占用多少空间来动态调整单元格大小。

答案 4 :(得分:8)

如果不调用sizeToFit,您可以使用非常即插即用的解决方案以数字方式完成所有操作:

+ (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;
}

我对动态分配高度的UITableViewCells使用了很多。

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

答案 5 :(得分:6)

复制&amp;粘贴此方法&amp;使用它像:

[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;
    }

答案 6 :(得分:4)

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

答案 7 :(得分:1)

Swift 4 要获得NSAttributedString的高度,请使用下面的此功能。 宽度的位置 - UILabelUITextView

的宽度
max-height: 100%;

要获得String的高度,请使用此函数,它与之前的方法几乎相同:

func getHeight(for attributedString: NSAttributedString, font: UIFont, width: CGFloat) -> CGFloat {
    let textStorage = NSTextStorage(attributedString: attributedString)
    let textContainter = NSTextContainer(size: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude))
    let layoutManager = NSLayoutManager()
    layoutManager.addTextContainer(textContainter)
    textStorage.addLayoutManager(layoutManager)
    textStorage.addAttribute(NSAttributedStringKey.font, value: font, range: NSMakeRange(0, textStorage.length))
    textContainter.lineFragmentPadding = 0.0
    layoutManager.glyphRange(for: textContainter)
    return layoutManager.usedRect(for: textContainter).size.height
}

答案 8 :(得分:0)

就我而言,我为每个部分使用固定大小标题,但每个标题中都包含动态单元格大小。 单元格的高度取决于标签的高度。

使用:

tableView.estimatedRowHeight = SomeNumber
tableView.rowHeight = UITableViewAutomaticDimension

使用时

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

当很多标题没有折叠时,会在框架重新加载动画时产生很多错误,例如标题重复(标题类型x在同一类型下)和奇怪的动画,即使使用类型.none (仅供参考,固定标题高度和单元格高度有效)。

解决方案是使用heightForRowAt回调并自行计算标签的高度(加上动画看起来很多更好)。请记住,高度被称为第一个

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
}

答案 9 :(得分:0)

这是我用于计算多行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)
    }
}

答案 10 :(得分:0)

您需要创建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)
}

您必须发送标签的宽度

答案 11 :(得分:0)

如果您使用的UILabel具有属性,则可以尝试方法textRect(forBounds:limitedToNumberOfLines)

这是我的示例:

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
label.numberOfLines = 0
label.text = "Learn how to use RxSwift and RxCocoa to write applications that can react to changes in your underlying data without you telling it to do so."

let rectOfLabel = label.textRect(forBounds: CGRect(x: 0, y: 0, width: 100, height: CGFloat.greatestFiniteMagnitude), limitedToNumberOfLines: 0)
let rectOfLabelOneLine = label.textRect(forBounds: CGRect(x: 0, y: 0, width: 100, height: CGFloat.greatestFiniteMagnitude), limitedToNumberOfLines: 1)
let heightOfLabel = rectOfLabel.height
let heightOfLine = rectOfLabelOneLine.height
let numberOfLines = Int(heightOfLabel / heightOfLine)

我在操场上的结果:

enter image description here

答案 12 :(得分:-1)

要使UILabel适合动态内容,可以在属性检查器中使用lines属性并将其设置为0。

而且您不需要为此进行任何编码。

有关更多详细信息,请查看下面的演示视频

https://www.youtube.com/watch?v=rVeDS_OGslU

答案 13 :(得分:-2)

如果您希望标签采用动态线条,您可以使用此

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));