11

当字体大小从用于创建它的字体大小减小时,我有一个 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 像素。

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

4

5 回答 5

17

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

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

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

于 2014-04-03T02:49:28.033 回答
2

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

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
  }
}
于 2018-07-09T12:50:44.537 回答
1

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

于 2015-05-22T15:28:52.350 回答
1

创建 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];
于 2017-04-24T08:14:43.347 回答
0

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

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

但是如果我们使用 aNSTextStorage创建属性字符串并调用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)
}

希望这可以帮助。

于 2015-08-24T07:58:33.273 回答