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

时间:2014-04-03 02:49:28

标签: ios objective-c ios7 fonts textkit

我有一个NSAttributedString报告一个boundingRectWithSize(并且扩展名为UITextView,它不正确地计算它的sizeThatFits)当字体大小从用于创建它的字体大小减少时。

在我执行类似操作的所有NSAttributedStrings上都没有发生,所以这里是重现的步骤。

  1. 使用不包含完整unicode字符集的非标准字体。
  2. 确保字符串中包含此字符中的字符"不支持"组。 iOS会将它们渲染为适当大小的Helvetica。
  3. 在NSAttributedString中的所有字体属性上缩放字体。我这样做的代码产生了这个问题。
  4. 从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添加,而这些属性似乎不在支持的属性列表here中。 NSOriginalFont发生了什么?为什么我的尺寸计算不正确?

4 个答案:

答案 0 :(得分:12)

我最终解决了这个问题,但发现网上缺乏关于它的信息,所以我决定在这里记录我的解决方案。

当使用的字体不支持字符串中的一个或多个字符时,将创建

NSOriginalFont个属性。 NSAttributedString添加了这些属性,这些属性跟踪在替换为Helvetica之前“假定”的字体。我可以编写一个有用的情况(你有时会运行大写字符串的全部字体:on?)但它对我没用。

实际上这是有害的。当我迭代我的字体相关属性以减小大小时,如上所示,文本的可见大小正在减小,但NSOriginalFont属性保留了对大尺寸的引用。

NSOriginalFont没有内置常量,但如果按名称调用它,则可以从NSMutableAttributedString中删除它。如果你这样做,你将开始从sizeThatFits,boundingRectWithSize和其他类似的函数得到正确的结果,假设你传递了正确的选项。

我最终在NSMutableAttributedString上创建了一个简单的类别方法,包含在下面,效果很好。

<强> 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

据推测,您可以简单地修改它以使其“同步”而不是完全删除它,但这对我来说对这个特定项目没用。

答案 1 :(得分:1)

不知道这是否有助于解决您的问题,但请查看我的解决方案,以便在此处自动调整文本UITextView:https://stackoverflow.com/a/30400391/1664123

答案 2 :(得分:1)

使用attributedString创建NSTextStorage对象和init。 并计算边界。

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

答案 3 :(得分:0)

要快速剥离,可以使用以下扩展名:

extension NSAttributedString {
  func strippedOriginalFont() -> NSAttributedString? {
    let mutableCopy = self.mutableCopy() as? NSMutableAttributedString
    mutableCopy?.removeAttribute(NSAttributedStringKey(rawValue: "NSOriginalFont"), range: NSMakeRange(0, self.length))
    return mutableCopy?.copy() as? NSAttributedString
  }
}