如何以固定宽度获取NSAttributedString的高度

bon*_*ldi 48 cocoa nstextview nsattributedstring appkit

我想在固定宽度的框中绘制一些NSAttributedStrings,但是在计算绘制它们时会占用的正确高度时遇到问题.到目前为止,我已经尝试过:

  1. 调用- (NSSize) size,但结果是无用的(为此目的),因为他们会给出字符串所需的宽度.

  2. - (void)drawWithRect:(NSRect)rect options:(NSStringDrawingOptions)options使用矩形调用我想要的宽度和NSStringDrawingUsesLineFragmentOrigin选项,就像我在绘图中使用的那样.结果......难以理解; 当然不是我想要的.(正如许多地方所指出的,包括这个 Cocoa-Dev线程).

  3. 创建一个临时的NSTextView并执行: 当我查询tmpView的框架时,宽度仍然是所需的,并且高度通常是正确的......直到我得到更长的字符串,当它通常是所需尺寸的一半时.(似乎没有最大尺寸被击中:一帧将是273.0高(约300太短),另一帧将是478.0(只有60-ish太短)).
    [[tmpView textStorage] setAttributedString:aString];
    [tmpView setHorizontallyResizable:NO];
    [tmpView sizeToFit];

如果有人管理过这个,我会感激任何指点.

Gra*_*iln 31

-[NSAttributedString boundingRectWithSize:options:]
Run Code Online (Sandbox Code Playgroud)

您可以指定NSStringDrawingUsesDeviceMetrics获取所有字形边界的并集.

与之不同-[NSAttributedString size],返回NSRect表示在绘制字符串时将更改的区域的尺寸.

正如@Bryan评论一样,boundingRectWithSize:options:在OS X 10.11及更高版本中已弃用(不推荐).这是因为字符串样式现在是动态的,具体取决于上下文.

对于OS X 10.11及更高版本,请参阅Apple的Calculating Text Height开发人员文档.

  • 坏消息:从OS 10.11开始不推荐使用此方法,它不再返回正确的高度.它太低了.但是,在10.10及以下版本中效果很好. (3认同)

bon*_*ldi 15

答案使用,
- (void)drawWithRect:(NSRect)rect options:(NSStringDrawingOptions)options
rect你传入的应该在你想要无限的维度中有0.0(呃,这是完全合理的).这里的例子.

  • 这个答案已经过时了.[格雷厄姆的答案](http://stackoverflow.com/a/2460091/39155)是截至2014年的正确方法. (2认同)

Rob*_*ger 6

您可能对Jerry Krinock的伟大(仅限OS X)NS(Attributed)String+Geometrics类别感兴趣,该类别旨在进行各种字符串测量,包括您正在寻找的内容.

  • 你是对的,问题是关于`NSTextView`,这是一个Mac类.当我回答这个问题时,我甚至不确定iOS是否有"NSAttributedString". (3认同)

Mat*_*t R 6

我有一个复杂的属性字符串与多个字体,并得到不正确的结果与我尝试的一些上述答案.使用UITextView给了我正确的高度,但对于我的用例来说太慢了(调整收集单元格).我使用之前引用并由Erik 描述的Apple文档中描述的相同通用方法编写了快速代码.这给了我正确的结果,必须比UITextView进行计算更快的执行.

private func heightForString(_ str : NSAttributedString, width : CGFloat) -> CGFloat {
    let ts = NSTextStorage(attributedString: str)

    let size = CGSize(width:width, height:CGFloat.greatestFiniteMagnitude)

    let tc = NSTextContainer(size: size)
    tc.lineFragmentPadding = 0.0

    let lm = NSLayoutManager()
    lm.addTextContainer(tc)

    ts.addLayoutManager(lm)
    lm.glyphRange(forBoundingRect: CGRect(origin: .zero, size: size), in: tc)

    let rect = lm.usedRect(for: tc)

    return rect.integral.size.height
}
Run Code Online (Sandbox Code Playgroud)