几篇帖子指出了从CTFramesetterSuggestFrameSizeWithConstraint中获得确切高度的困难,在这里,(framesetter帖子),@Chris DeSalvo给出了看起来像是最终修复的方法:添加具有正确行距调整的段落样式设置。
DeSalvo通过从其lineHeight中删除UIFont的上升器和下降器来获得他的"领先"。我想知道这与CTFontGetLeading
相比如何.
我使用了像这样创建的字体:
CTFontRef fontr = CTFontCreateWithName((CFStringRef)@"Helvetica Neue", 16.0f, NULL);
UIFont *font = [UIFont fontWithName:@"Helvetica Neue" size:16.0f];
值完全不同:
- 0.448 CTFontGetLeading(英语:CTFontGetLeading)
- 2.360 德萨尔沃公式:UIFont 线高度 - 上升 + 下降
下面是一些其他 UIFont 值:
- 21.000 UIFont的线高度
- 15.232 UIFont 的上升器(基线的 Y 坐标)
- -3.408 UIFont 的下行者(基线的 Y 坐标)
- 08.368 UIFont的xHeight
以下是Ken Thomases询问的CTFont价值观:
- 11.568001 CTFontGetCapHeight
- 08.368 CTFontGetXHeight
- -15.216001, -7.696001, 38.352001, 24.928001 CTFontGetBoundingBox
- 15.232 CTFontGetAscent
- 03.408 CTFontGetDescent(类引用说"根据字体引用的点大小和矩阵缩放的缩放字体下降度量" - 这显然意味着它是基线中Y坐标的绝对值?
我注意到 UIFont 以前有一个专门用于"领导"的属性,但它已被弃用,建议我们改用lineHeight
。所以UIFont认为相同的字体会导致21和CTFontRef .448?有些不对劲。
三个问题:
- "领先"真的是kCTParagraphStyleSpecifierLineSpacingAdjust的含义吗?
- 如果是这样,我应该使用哪种方法/公式来获取它?
- 如果没有,我应该使用什么来调整行距?
我也遇到了这个问题,这是在实际项目中工作的代码:
// When you create an attributed string the default paragraph style has a leading
// of 0.0. Create a paragraph style that will set the line adjustment equal to
// the leading value of the font. This logic will ensure that the measured
// height for a given paragraph of attributed text will be accurate wrt the font.
- (void) applyParagraphAttributes:(CFMutableAttributedStringRef)mAttributedString
{
CGFloat leading = CTFontGetLeading(self.plainTextFont);
CTParagraphStyleSetting paragraphSettings[1] = {
kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof (CGFloat), &leading
};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(paragraphSettings, 1);
CFRange textRange = CFRangeMake(0, [self length]);
CFStringRef keys[] = { kCTParagraphStyleAttributeName };
CFTypeRef values[] = { paragraphStyle };
CFDictionaryRef attrValues = CFDictionaryCreate(kCFAllocatorDefault,
(const void**)&keys,
(const void**)&values,
sizeof(keys) / sizeof(keys[0]),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
BOOL clearOtherAttributes = FALSE;
CFAttributedStringSetAttributes(mAttributedString, textRange, attrValues, (Boolean)clearOtherAttributes);
CFRelease(attrValues);
CFRelease(paragraphStyle);
self.stringRange = textRange;
return;
}
回答我上面的 3 个问题:
- 是的,"领先"实际上是什么意思 kCTParagraphStyleSpecifierLineSpacingAdjust。或者无论如何,它按预期工作。
- 使用
CTFontGetLeading(fontRef)
获取字体的正常行距,或插入您选择的任何值(作为 CGFloat)。 - 不适用。
答案 1 和 2 有效:在属性字符串的 paragraphStyle 属性中指定前导值将使核心文本帧设置器能够精确计算其高度。
有两个注意事项:
- 如果您尝试以增量方式计算高度,一次一个字符串,每个字符串包含一个初始换行符,则 framesetter 会将该换行符视为表示整行,而不仅仅是行距。如果你想要串联字符串的高度,你必须将该串联馈送到框架设置器。当然,您可以跟踪增量高度差异,但无法避免让框架设置者重新计算早期的字符串尺寸。
- CATextLayer 忽略间距调整(和其他属性)。如果每个精确字符串高度的成帧是一个问题,则必须直接绘制到 CALayer。
还有一个谜团:UIFont 弃用的领导是怎么回事?行距和行高是两个不同的东西。