如何动态计算UILabel高度?

时间:2023-02-01 08:34:09

I want to calculate number of lines and height of UILabel dynamically from given text for same.

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

12 个解决方案

#1


81  

Try this

试试这个

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

or

int lines = labelHeight/16;

NSLog(@"lines count : %i \n\n",lines);  

or

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

By Using Categories, Just Create the category class named as

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

UILabel+UILabelDynamicHeight.h

UILabel + UILabelDynamicHeight.h

UILabel+UILabelDynamicHeight.m

UILabel + UILabelDynamicHeight.m

No more tension about the height calculation. Please review the below implementation.

高度计算不再紧张。请审阅下面的实现。

Updates for iOS7 & Above,iOS 7 below : Dynamically calculate the UILabel height

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

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

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

#2


49  

Calling -sizeToFit on UILabel instance will automatically resize it to fit text it displays, no calculating required. If you need the size, you can get it from label's frame property after that.

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

#3


23  

To summarize, you can calculate the height of a label by using its string and calling boundingRectWithSize. You must provide the font as an attribute, and include .usesLineFragmentOrigin for multi-line labels.

总之,您可以使用它的字符串和调用boundingRectWithSize来计算标签的高度。您必须提供字体作为一个属性,并包含. 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

Some extensions to do just that:

有一些扩展可以做到这一点:

Swift Version:

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 Version:

UILabel+Utility.h

UILabel + Utility.h

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

UILabel+Utility.m

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

#4


17  

The current solution has been deprecated as of iOS 7.

目前的解决方案在ios7中已经被弃用。

Here is an updated solution:

这里有一个更新的解决方案:

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

The reason that my solution is set up like this is because I am using a UITableViewCell and resizing the cell dynamically relative to how much room the label will take up.

我这样设置解决方案的原因是,我使用UITableViewCell,并根据标签占用的空间动态调整单元格的大小。

#5


7  

Without calling sizeToFit, you can do this all numerically with a very plug and play solution:

不需要调用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;
}

I use it a lot for UITableViewCells that have dynamically allocated heights.

我经常在UITableViewCells用它来动态分配高度。

Solves the attributes problem as well @Salman Zaidi.

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

#6


5  

Copy & paste this method & used It like:

复制粘贴此方法,使用方法如下:

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

#7


4  

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

#8


1  

Swift 4 To get height for the NSAttributedString use this function below. Where width - the width of your UILabel or UITextView

要获得NSAttributedString的高度,请使用下面的函数。哪里的宽度-你的UILabel或UITextView的宽度

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
}

To get height for String use this function, It is almost identical like the previous method:

使用此函数可以得到字符串的高度,与之前的方法几乎相同:

func getHeight(for string: String, font: UIFont, width: CGFloat) -> CGFloat {
    let textStorage = NSTextStorage(string: string)
    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
}

#9


0  

In my case, I was using a fixed size header for each section but with a dynamically cell size in each header. The cell's height, depends on the label's height.

在我的例子中,我为每个部分使用了一个固定大小的标题,但是每个标题中都有一个动态的单元格大小。细胞的高度,取决于标签的高度。

Working with:

处理:

tableView.estimatedRowHeight = SomeNumber
tableView.rowHeight = UITableViewAutomaticDimension

Works but when using:

但是当使用:工作

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

when a lot of headers are not collapsed, creates a lot of bugs such as header duplication (header type x below the same type) and weird animations when the framework reloads with animation, even when using with type .none (FYI, a fixed header height and cell height works).

当很多页眉没有被折叠时,就会产生很多bug,比如页眉重复(页眉类型x在同一类型之下),以及当框架重新加载动画时产生的奇怪的动画,即使是在使用.none类型时(FYI,固定的页眉高度和单元格高度可以工作)。

The solution is making the use of heightForRowAt callback and calculate the height of the label by your self (plus the animation looks a lot better). Remember that the height is being called first.

解决方案是使用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
}

#10


0  

This is the extension I use for calculating multiline UILabel heights, it's an adjusted snippet from a previous stack overflow post:

这是我用来计算多行UILabel高度的扩展,它是从以前的一个栈溢出post中调整过来的代码片段:

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

#11


0  

You need to create an extension of String and call this method

您需要创建字符串的扩展名并调用此方法

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

You must send the width of your label

你必须发送你的标签的宽度

#12


-2  

if you want the label to take dynamic lines you may use this

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

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

#1


81  

Try this

试试这个

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

or

int lines = labelHeight/16;

NSLog(@"lines count : %i \n\n",lines);  

or

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

By Using Categories, Just Create the category class named as

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

UILabel+UILabelDynamicHeight.h

UILabel + UILabelDynamicHeight.h

UILabel+UILabelDynamicHeight.m

UILabel + UILabelDynamicHeight.m

No more tension about the height calculation. Please review the below implementation.

高度计算不再紧张。请审阅下面的实现。

Updates for iOS7 & Above,iOS 7 below : Dynamically calculate the UILabel height

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

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

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

#2


49  

Calling -sizeToFit on UILabel instance will automatically resize it to fit text it displays, no calculating required. If you need the size, you can get it from label's frame property after that.

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

#3


23  

To summarize, you can calculate the height of a label by using its string and calling boundingRectWithSize. You must provide the font as an attribute, and include .usesLineFragmentOrigin for multi-line labels.

总之,您可以使用它的字符串和调用boundingRectWithSize来计算标签的高度。您必须提供字体作为一个属性,并包含. 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

Some extensions to do just that:

有一些扩展可以做到这一点:

Swift Version:

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 Version:

UILabel+Utility.h

UILabel + Utility.h

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

UILabel+Utility.m

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

#4


17  

The current solution has been deprecated as of iOS 7.

目前的解决方案在ios7中已经被弃用。

Here is an updated solution:

这里有一个更新的解决方案:

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

The reason that my solution is set up like this is because I am using a UITableViewCell and resizing the cell dynamically relative to how much room the label will take up.

我这样设置解决方案的原因是,我使用UITableViewCell,并根据标签占用的空间动态调整单元格的大小。

#5


7  

Without calling sizeToFit, you can do this all numerically with a very plug and play solution:

不需要调用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;
}

I use it a lot for UITableViewCells that have dynamically allocated heights.

我经常在UITableViewCells用它来动态分配高度。

Solves the attributes problem as well @Salman Zaidi.

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

#6


5  

Copy & paste this method & used It like:

复制粘贴此方法,使用方法如下:

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

#7


4  

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

#8


1  

Swift 4 To get height for the NSAttributedString use this function below. Where width - the width of your UILabel or UITextView

要获得NSAttributedString的高度,请使用下面的函数。哪里的宽度-你的UILabel或UITextView的宽度

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
}

To get height for String use this function, It is almost identical like the previous method:

使用此函数可以得到字符串的高度,与之前的方法几乎相同:

func getHeight(for string: String, font: UIFont, width: CGFloat) -> CGFloat {
    let textStorage = NSTextStorage(string: string)
    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
}

#9


0  

In my case, I was using a fixed size header for each section but with a dynamically cell size in each header. The cell's height, depends on the label's height.

在我的例子中,我为每个部分使用了一个固定大小的标题,但是每个标题中都有一个动态的单元格大小。细胞的高度,取决于标签的高度。

Working with:

处理:

tableView.estimatedRowHeight = SomeNumber
tableView.rowHeight = UITableViewAutomaticDimension

Works but when using:

但是当使用:工作

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

when a lot of headers are not collapsed, creates a lot of bugs such as header duplication (header type x below the same type) and weird animations when the framework reloads with animation, even when using with type .none (FYI, a fixed header height and cell height works).

当很多页眉没有被折叠时,就会产生很多bug,比如页眉重复(页眉类型x在同一类型之下),以及当框架重新加载动画时产生的奇怪的动画,即使是在使用.none类型时(FYI,固定的页眉高度和单元格高度可以工作)。

The solution is making the use of heightForRowAt callback and calculate the height of the label by your self (plus the animation looks a lot better). Remember that the height is being called first.

解决方案是使用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
}

#10


0  

This is the extension I use for calculating multiline UILabel heights, it's an adjusted snippet from a previous stack overflow post:

这是我用来计算多行UILabel高度的扩展,它是从以前的一个栈溢出post中调整过来的代码片段:

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

#11


0  

You need to create an extension of String and call this method

您需要创建字符串的扩展名并调用此方法

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

You must send the width of your label

你必须发送你的标签的宽度

#12


-2  

if you want the label to take dynamic lines you may use this

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

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