CoreText.如何计算属性字符串的边界框?

dug*_*gla 14 nsattributedstring core-text

在CoreText中,很容易问:"对于给定的矩形,这个属性字符串有多少适合?".

CTFrameGetVisibleStringRange(rect).length
Run Code Online (Sandbox Code Playgroud)

将返回字符串中的下一行文本应该开始的位置.

我的问题是:"给定一个属性字符串和宽度,我需要什么矩形高度来完全绑定属性字符串?".

CoreText框架是否提供了执行此操作的工具?

谢谢,
道格

Jos*_*hua 23

你需要的是CTFramesetterSuggestFrameSizeWithConstraints(),你可以像这样使用它:

CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attributedString)); /*Create your framesetter based in you NSAttrinbutedString*/
CGFloat widthConstraint = 500; // Your width constraint, using 500 as an example
CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(
   framesetter, /* Framesetter */
   CFRangeMake(0, text.length), /* String range (entire string) */
   NULL, /* Frame attributes */
   CGSizeMake(widthConstraint, CGFLOAT_MAX), /* Constraints (CGFLOAT_MAX indicates unconstrained) */
   NULL /* Gives the range of string that fits into the constraints, doesn't matter in your situation */
);
CGFloat suggestedHeight = suggestedSize.height;
Run Code Online (Sandbox Code Playgroud)

编辑

//IMPORTANT: Release the framesetter, even with ARC enabled!
CFRelease(frameSetter);
Run Code Online (Sandbox Code Playgroud)

由于ARC仅发布Objective-C对象,而CoreText处理C,因此很可能在此处发生内存泄漏.如果你NSAttributedString的身材很小并且你做了一次,你不应该有任何不良后果.但是,如果你有一个循环来计算,比方说,大/复数NSAttributedStrings的50个高度,并且你没有释放它CTFramesetterRef,你可能会有严重的内存泄漏.查看链接的教程,了解有关内存泄漏和使用仪器进行调试的更多信息.

所以这个问题的解决方案是添加 CFRelease(frameSetter);

  • Downvoting因为这种方法从未奏效(在iOS 5 + 6 + 7中尝试过 - 它在所有iOS版本中都有重大缺陷).iOS 6的臭虫是臭名昭着的(苹果虚假地增加宽度,耗尽空间,删除最后一行高度),但它确实愚蠢的事情,如忽略字形并假设每个字符都是"f"或"g",尽管输入参数,以防止这个问题. (3认同)