NSAttributedString中字距调整的不一致行为

问题描述 投票:4回答:2

我需要使用Kern attributeNSAttributedString。正如我在文档中看到的那样,该属性的默认值为0.0。但我面对短语Hello, world的奇怪行为(短语“你好”一切都很好):

NSDictionary<NSString*, id>* attributes = @{NSFontAttributeName: [UIFont systemFontOfSize:12]};
NSString* text = @"Hello, World";
NSAttributedString* string = [[NSAttributedString alloc] initWithString:text attributes:attributes];
CGSize size1 = [string size];

NSMutableDictionary<NSString*, id>* attributesWithKernel = [attributes mutableCopy];
attributesWithKernel[NSKernAttributeName] = @(0.0);
NSAttributedString* stringWithKern = [[NSAttributedString alloc] initWithString:text attributes:attributesWithKernel];
CGSize size2 = [stringWithKern size];   
XCTAssertTrue(CGSizeEqualToSize(size1, size2)); //here test falls
//size1 = size1 = (width = 68.8125, height = 14.3203125)
//size2 = (width = 69.515625, height = 14.3203125)

为了使size1和size2相等,字距调整应该等于-7.105427357601002e-15,我知道这非常接近0.0,但它很奇怪,因为这会改变宽度几乎是一个像素。 NSAttributedStringObjective-CSwift中具有相同的行为,例如swift:

    let text = "Hello, World"
    let attributes : [NSAttributedString.Key : Any] = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: UIFont.systemFontSize)]
    let str = NSAttributedString(string: text, attributes: attributes)
    let size = str.size()

    var attributesWithKern = attributes
    attributesWithKern[NSAttributedString.Key.kern] = NSNumber(value: 0.0)
    let strWithKern = NSAttributedString(string: text, attributes: attributesWithKern)
    let sizeWithKern = strWithKern.size()

    XCTAssertTrue(size == sizeWithKern)

我怎么能解决这个问题?

附:现在我只是从属性字符串中删除NSKernAttributeKey,如果键等于0.0,但我不认为这是一个很好的解决方案。

ios objective-c swift nsattributedstring kerning
2个回答
2
投票

我相信这里的文档是错误的,值得为此开一个radar。如果未设置任何值,则将其解释为“正常字距调整”。当设置为0时,它被解释为“禁用字距调整”,这就是为什么宽度稍微宽一点(字距调整通常略微为负,带来kern-pair字符,如“W”和“o”在这个字体中,有点更近)。我认为没有任何方法可以在不删除属性的情况下明确请求“默认字距调整”。

出于您的目的,我相信您通过在零值时删除值来做正确的事情,因为您需要默认字距调整,而不是禁用字距调整。

你的微小负值正在起作用的原因是因为它不是零,所以它不会禁用字距调整,但它很小,行为非常非常接近默认值,而你在中间计算中遇到Double的精度(或者可能是Float的精度,取决于它在内部的实现方式)。您应该发现您的测试通过的任何值都小于(接近于零),而不仅仅是该值。例如,在我的测试中,正7e-15也有效。


1
投票

我根据你的代码做了一些测试,我确认这个行为看起来像一个bug。关键是一些字母字符串是相等的,有些则不是。例如,具有“Hello Mo”或“Hello Oo”的字符串是相等的,但是例如“Hello WoWoWo”相差很多。所以我们在这里看到为“W”添加了一些字距,没有任何理由。它也可以取决于所选的字体,但我没有测试它。我在这里看到你使用的唯一解决方案 - 删除NSKernAttributeKey,如果它等于0。

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.