【问题标题】:NSAttributedString reporting incorrect sizes for UITextView sizeThatFits and boundingRectWithSize with correct options setNSAttributedString 报告 UITextView sizeThatFits 和 boundingRectWithSize 的大小不正确,并设置了正确的选项
【发布时间】:2014-05-14 15:36:57
【问题描述】:

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

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

  1. 使用不包含完整 unicode 字符集的非标准字体。
  2. 确保字符串包含此“不受支持”集中的字符。 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 以了解文本何时足够小以适合在某些情况下我会发生零竞赛。对于任何小于我开始时的字体值(恰好是 50 像素),高度都被计算为 60 像素。

NSLog NSAttributedString 时,我发现有几个属性我没有使用键NSOriginalFont 添加,它似乎不在支持的属性列表here 中。 NSOriginalFont 是怎么回事?为什么我的尺寸计算不正确?

【问题讨论】:

  • 对于遇到此问题的其他人,可以创建此属性的另一种方法是,如果您已从 UITextView 读取属性字符串,在某些情况下可能会插入该属性。

标签: ios objective-c ios7 fonts textkit


【解决方案1】:

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

NSOriginalFont 属性在使用的字体不支持字符串中的一个或多个字符时创建。 NSAttributedString 添加这些属性来跟踪字体在替换到 Helvetica 之前“应该”是什么。我可以弥补一个有用的情况(你有时会运行大写字符串的全大写字体?)但它对我没有用。

事实上它是有害的。当我遍历与字体相关的属性以减小大小时,如上所示,文本的可见大小正在减小,但 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

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

【讨论】:

  • 为什么不直接使用 [self removeAttribute:@"NSOriginalFont" range:NSMakeRange( 0, self.length )]?
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

    但是如果我们使用NSTextStorage来创建attributedString并调用textView.setAttributedText,那么它就不会添加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)
    }
    

    希望这会有所帮助。

    【讨论】:

      【解决方案4】:

      创建 NSTextStorage 对象并使用属性字符串进行初始化。 并计算界限。

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

      【讨论】:

        【解决方案5】:

        为了快速剥离,您可以使用这个扩展:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-04-10
          • 1970-01-01
          • 1970-01-01
          • 2014-04-17
          • 1970-01-01
          • 2021-02-18
          相关资源
          最近更新 更多