如何获得固定宽度的NSAttributedString的高度

我想在固定宽度的框中做一些NSAttributedStrings的绘图,但是在绘制时计算正确的高度会遇到困难。 到目前为止,我已经尝试过:

  1. 调用- (NSSize) size ,但结果是无用的(为此目的),因为他们会给任何宽度string的期望。

  2. 调用- (void)drawWithRect:(NSRect)rect options:(NSStringDrawingOptions)options与矩形矩形我想要的宽度和NSStringDrawingUsesLineFragmentOrigin在选项中,完全按照我在我的绘图中使用。 结果是…难以理解; 当然不是我要找的东西。 (正如在许多地方指出的,包括这个 Cocoa-Dev线程)。

  3. 创build一个临时的NSTextView并执行:
    [[tmpView textStorage] setAttributedString:aString];
    [tmpView setHorizontallyResizable:NO];
    [tmpView sizeToFit];

    当我查询tmpView的框架,宽度仍然是所需要的,高度往往是正确的…直到我得到更长的string,当它通常是一半所需的大小。 (似乎没有一个最大的大小被击中:一个框架将是273.0高(约300太短),另一个将是478.0(只有60 ish太短))。

我会很感激任何指针,如果任何人已经pipe理了这一点。

 -[NSAttributedString boundingRectWithSize:options:] 

您可以指定NSStringDrawingUsesDeviceMetrics来获得所有字形边界的联合 。

-[NSAttributedString size] ,返回的NSRect表示在绘制string时将会改变的区域的尺寸。

作为@Bryan注释, boundingRectWithSize:options:在OS X 10.11及更高版本中被弃用(不推荐)。 这是因为string样式现在是dynamic的,取决于上下文。

对于OS X 10.11及更高版本,请参阅Apple的计算文本高度开发者文档。

答案使用
- (void)drawWithRect:(NSRect)rect options:(NSStringDrawingOptions)options
但是你通过的rect应该在你想要的无限维数中是0.0(呃,这是非常有意义的)。 这里的例子。

您可能会对Jerry Krinock伟大的(仅限OS X) NS(Attributed)String+Geometrics类别感兴趣,该类别旨在执行各种string测量,包括您要查找的内容。

使用NSAttributedString方法

 - (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context 

尺寸是对该区域的约束,计算的区域宽度被限制为指定的宽度,而基于该宽度的高度是灵活的。 如果不可用,可以指定nil作为上下文。 要获得多行文本大小,请使用NSStringDrawingUsesLineFragmentOrigin来获取选项。

我只是浪费了一大堆时间,所以我提供了一个额外的答案来挽救他人。 格雷厄姆的答案是90%正确的,但它缺less一个关键部分:

要用-boundingRectWithSize:options:获得准确的结果, 您必须通过以下选项

 NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesDeviceMetrics|NSStringDrawingUsesFontLeading` 

如果你省略lineFragmentOrigin之一,你会得到废话回来; 返回的矩形将是单线高,并不会完全尊重您传入方法的大小。

为什么这是如此复杂,如此糟糕的logging是超越我的。 但是你现在有了。 通过这些选项,它会完美的工作(至less在OS X上)。

在OS X 10.11+上,以下方法适用于我(从Apple的“ 计算文本高度”文档)

 - (CGFloat)heightForString:(NSAttributedString *)myString atWidth:(float)myWidth { NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:myString]; NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize: NSMakeSize(myWidth, FLT_MAX)]; NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; [layoutManager addTextContainer:textContainer]; [textStorage addLayoutManager:layoutManager]; [layoutManager glyphRangeForTextContainer:textContainer]; return [layoutManager usedRectForTextContainer:textContainer].size.height; } 

在这个页面上没有一个答案适用于我,也没有从苹果的文档中古老的Objective-C代码。 我终于做了一个UITextView工作是首先设置它的textattributedText text attributedText ,然后计算所需的大小,如下所示:

 let size = textView.sizeThatFits(CGSize(width: maxWidth, height: CGFloat.max)) 

完美的作品。 Booyah!

Swift 3:

 let attributedStringToMeasure = NSAttributedString(string: textView.text, attributes: [ NSFontAttributeName: UIFont(name: "GothamPro-Light", size: 15)!, NSForegroundColorAttributeName: ClickUpConstants.defaultBlackColor ]) let placeholderTextView = UITextView(frame: CGRect(x: 0, y: 0, width: widthOfActualTextView, height: 10)) placeholderTextView.attributedText = attributedStringToMeasure let size: CGSize = placeholderTextView.sizeThatFits(CGSize(width: widthOfActualTextView, height: CGFloat.greatestFiniteMagnitude)) height = size.height 

这个答案很适合我,不像其他那些给我不正确的高度的大string。

如果您想使用常规文本而不是属性文本执行此操作,请执行以下操作:

 let placeholderTextView = UITextView(frame: CGRect(x: 0, y: 0, width: ClickUpConstants.screenWidth - 30.0, height: 10)) placeholderTextView.text = "Some text" let size: CGSize = placeholderTextView.sizeThatFits(CGSize(width: widthOfActualTextView, height: CGFloat.greatestFiniteMagnitude)) height = size.height 

正如上面提到的很多家伙,并基于我的testing。

我使用open func boundingRect(with size: CGSize, options: NSStringDrawingOptions = [], context: NSStringDrawingContext?) -> CGRect在iOS的open func boundingRect(with size: CGSize, options: NSStringDrawingOptions = [], context: NSStringDrawingContext?) -> CGRect像这样bellow:

 let rect = attributedTitle.boundingRect(with: CGSize(width:200, height:0), options: NSStringDrawingOptions.usesLineFragmentOrigin, context: nil) 

这里的200是固定的宽度,因为你期望的, 我给它的高度为0,因为我认为这样更好,告诉API高度是无限的

选项不是那么重要,我试着用.usesLineFragmentOrigin.usesLineFragmentOrigin.union(.usesFontLeading).usesLineFragmentOrigin.union(.usesFontLeading).union(.usesDeviceMetrics) ,它给出相同的结果。

结果是我的预期。

谢谢。

    Interesting Posts