我需要使用NSAttributedString
中的Kern attribute。正如我在文档中看到的那样,该属性的默认值为0.0。但是我遇到短语Hello, world
(短语“ Hello”都很好)的奇怪行为:
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,但这很奇怪,因为这几乎改变了像素宽度。
NSAttributedString
在Objective-C
和Swift
中具有相同的行为,例如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)
我该如何解决此问题?
PS
现在,如果键等于0.0,我只是从属性字符串中删除NSKernAttributeKey
,但我认为这不是一个好的解决方案。
答案 0 :(得分:2)
我相信这里的文档是错误的,值得为此公开radar。如果未设置任何值,则将其解释为“常规字距调整”。设置为0时,它被解释为“禁用字距调整”,这就是为什么宽度稍宽(字距调整通常为负数的原因,该字型中的字距对字符(如“ W”和“ o”)略微变了一点。更接近)。我认为没有任何方法可以在不删除属性的情况下明确请求“默认字距调整”。
出于您的目的,我相信您可以通过删除零值来做正确的事,因为您希望使用默认字距调整而不是禁用字距调整。
您的微小负值起作用的原因是因为它不为零,因此它不会禁用字距调整,但是它很小以至于行为非常非常接近默认值,并且您会遇到Double in的精度中间计算(或者可能是Float的精度,取决于它在内部的实现方式)。您应该发现测试通过的任何值都小于(接近于零)小于此值,而不仅仅是该值。在我的测试中,例如,阳性7e-15也会起作用。
答案 1 :(得分:1)