如何计算 NSAttributedString 的高度,给定宽度和行数?

Posted

技术标签:

【中文标题】如何计算 NSAttributedString 的高度,给定宽度和行数?【英文标题】:How to calculate the height of NSAttributedString, given width and number of lines? 【发布时间】:2013-09-19 06:53:05 【问题描述】:

我想显示 3 行 NSAttributedString。有没有办法根据宽度和行数计算出所需的高度?

而且我不想创建 UILabel 来进行大小计算,因为我希望在后台线程中完成计算。

【问题讨论】:

在其他问题中有办法做到这一点 - ***.com/questions/42171468/… 【参考方案1】:

我想知道为什么这仍然没有答案。无论如何,这是最适合我的方法。

创建一个名为“Height”的 NSAttributedString 类别。这应该会生成两个名为“NSAttributedString+Height.h,m”的文件

.h 文件中:

@interface NSAttributedString (Height)  
-(CGFloat)heightForWidth:(CGFloat)width;  
@end  

.m 文件中:

-(CGFloat)heightForWidth:(CGFloat)width  
  
    return ceilf(CGRectGetHeight([self boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
                                                    options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading
                                                    context:nil])) + 1;  

这是发生了什么:

    boundRectWithSize:options:context 得到一个矩形,它被限制为您传递给该方法的宽度。 NSStringDrawingUsesLineFragmentOrigin 选项告诉它期待多行字符串。 然后我们从该矩形中获取高度参数。 在 ios 7 中,此方法返回小数。我们需要一个圆形的图形。 ceilf 对此有所帮助。 我们为返回值添加了一个额外的单位。

这里是如何使用它

NSAttributedString *string = ...
CGFloat height = [string heightForWidth:320.0f];

您可以使用该高度进行布局计算。

【讨论】:

@ezinezync 你只是计算指定宽度内的高度,但是如何将高度限制为3行??? @0oneo 为此,您必须限制标签本身的numberOfLines。我现在想不出另一种方法来做到这一点。 这不是在回答问题,主要问题是numberOfLines 这真的很难,因为 NSAttributedString 可以包含各种内容(甚至图像)。对我来说,这似乎真的很难解决。【参考方案2】:

@dezinezync 的回答回答了一半的问题。您只需计算给定宽度和行数的 UILabel 允许的最大尺寸。

首先,根据行数获取允许的高度:

let maxHeight = font.lineHeight * numberOfLines

然后根据条件计算你设置的文本的边界矩形:

let labelStringSize = yourText.boundingRectWithSize(CGSizeMake(CGRectGetWidth(self.frame), maxHeight),
            options: NSStringDrawingOptions.UsesLineFragmentOrigin,
            attributes: [NSFontAttributeName: font],
            context: nil).size

【讨论】:

【参考方案3】:

TTTAttributedLabel中有一个方法被调用

+ (CGSize)sizeThatFitsAttributedString:withConstraints:limitedToNumberOfLines:

基本上,这个方法使用一些Core Text API来计算高度,关键函数是

CGSize CTFramesetterSuggestFrameSizeWithConstraints(
    CTFramesetterRef framesetter,
    CFRange stringRange,
    CFDictionaryRef __nullable frameAttributes,
    CGSize constraints,
    CFRange * __nullable fitRange )

我认为,也被

使用

- (CGRect)textRectForBounds:limitedToNumberOfLines:


这是一种解决方法,我认为有更好的方法...

static UILabel *label;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
    label = [UILabel new];
);
label.attributedText = givenAttributedString;
CGRect rect = CGRectMake(0,0,givenWidth,CGFLOAT_MAX)
CGFloat height = [label textRectForBounds:rect
                        limitedToNumberOfLines:2].size.height;

【讨论】:

以上是关于如何计算 NSAttributedString 的高度,给定宽度和行数?的主要内容,如果未能解决你的问题,请参考以下文章

计算含有表情文字的NSAttributedString的size

如何从 NSAttributedString 获取图像数据

你如何使用 NSAttributedString?

NSAttributedString

你如何使用NSAttributedString?

你如何抚摸 NSAttributedString 的 _outside_ ?