NSAttributedString为UITextView sizeThatFits和boundingRectWithSize报告不正确的大小,并设置了正确的选项
我有一个NSAttributedString报告一个boundingRectWithSize(和扩展UITextView不正确地计算其sizeThatFits)当字体大小从用于创build它的字体大小减less。
它不会发生在我做类似的操作的所有NSAttributedStrings,所以这里是重现的步骤。
- 使用不包含完整Unicode字符集的非标准字体。
- 确保string包含此“不受支持”集中的字符。 iOS会将它们渲染为Helvetica,大小适中。
- 在您的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) }
希望这可以帮助。