NSAttributedString为UITextView sizeThatFits和boundingRectWithSize报告不正确的大小,并设置了正确的选项

我有一个NSAttributedString报告一个boundingRectWithSize(和扩展UITextView不正确地计算其sizeThatFits)当字体大小从用于创build它的字体大小减less。

它不会发生在我做类似的操作的所有NSAttributedStrings,所以这里是重现的步骤。

  1. 使用不包含完整Unicode字符集的非标准字体。
  2. 确保string包含此“不受支持”集中的字符。 iOS会将它们渲染为Helvetica,大小适中。
  3. 在您的NSAttributedString中缩放字体的所有字体属性。 我的代码这样做产生的问题看起来像这样。

从UITextView子类中:

NSMutableAttributedString *mutableString = [self.attributedText mutableCopy]; [mutableString enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, mutableString.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { if (value) { UIFont *oldFont = (UIFont *)value; UIFont *newFont = [oldFont fontWithSize:oldFont.pointSize - 1]; [mutableString removeAttribute:NSFontAttributeName range:range]; [mutableString addAttribute:NSFontAttributeName value:newFont range:range]; } }]; self.attributedText = [mutableString copy]; 

我注意到,当在while循环中运行这个代码时,检查sizeThatFits来知道文本何时足够小,以至于在某些情况下我会产生一个零竞赛。 对于任何小于我开始使用的字体值的情况,高度计算为60px,这恰好是50px。

NSLog的NSAttributedString我发现有几个属性,我没有添加关键的NSOriginalFont这似乎不在支持的属性列表在这里 。 什么是NSOriginalFont? 为什么我的尺寸计算不正确?

我最终解决了这个问题,但是发现networking上的信息不足,所以我决定在这里logging我的解决scheme。

当使用的字体不支持string中的一个或多个字符时,会创buildNSOriginalFont属性。 NSAttributedString添加了这些属性,用于跟踪在Helvetica发生replace之前字体“假定”的字体。 我可以弥补这种情况,这是有用的(你有时运行大写字母:on?的全大写字体),但它对我没有用。

其实这是有害的。 正如我重复我的字体相关的属性,以减less大小如上所示文本的可见大小减less,但NSOriginalFont属性保留大尺寸的引用。

NSOriginalFont没有内置的常量,但是如果你通过名称来调用它,可以从NSMutableAttributedString中去掉它。 如果你这样做,你将开始从sizeThatFits,boundingRectWithSize和其他类似的函数得到适当的结果,假设你传递正确的选项。

我最终在NSMutableAttributedString上创build了一个简单的类别方法,这个方法很好。

NSMutableAttributedString + StripOriginalFont.h

 @interface NSMutableAttributedString (StripOriginalFont) - (void) stripOriginalFont; @end 

NSMutableAttributedString + StripOriginalFont.m

 @implementation NSMutableAttributedString (StripOriginalFont) - (void) stripOriginalFont{ [self enumerateAttribute:@"NSOriginalFont" inRange:NSMakeRange(0, self.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { if (value){ [self removeAttribute:@"NSOriginalFont" range:range]; } }]; } @end 

据推测,你可以简单地修改它以保持“同步”,而不是完全删除它,但对于这个特定的项目我没有用。

创buildNSTextStorage对象并使用其中的string进行初始化。 并计算边界。

 NSTextStorage *attributedText = [[NSTextStorage alloc] initWithAttributedString:[[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName:systemFont}]]; CGRect textRect = [attributedText boundingRectWithSize:CGSizeMake(textW, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil]; 

不知道这是否有助于解决您的问题,但看看我的解决scheme自动调整文本UITextView在这里: https : //stackoverflow.com/a/30400391/1664123

我有同样的问题。 当我调用NSOriginalFont textView.setAttributedString() ,它会自动为我添加NSOriginalFont属性,导致错误的大小。 我也使用sizeThatFits来计算高度。

我们得到错误的大小的原因是NSOriginalFont使用NSOriginalFont来计算不适合更改NSFont

但是如果我们使用NSTextStorage来创build属性NSTextStorage ,并调用NSTextStorage ,那么它将不会添加NSOriginalFont (我不知道为什么,但是这解决了我的问题),并计算大小将得到正确的答案。

简单代码:

 func getAttributedStringForTextView(content: String) -> NSAttributedString { var attriString = NSMutableAttributedString(string: content) // add attributes here ... // at last, use an NSTextStorage to wrap the result return NSTextStorage(attributedString: attriString) } 

希望这可以帮助。