3

有几篇文章指出了从 CTFramesetterSuggestFrameSizeWithConstraints 中获得精确高度的困难,在这里,(framesetter post),@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
  • 2.360 DeSalvo 的公式:UIFont lineHeight - assender + descender

以下是一些其他 UIFont 值:

  • 21.000 UIFont 的 lineHeight
  • 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 认为leading 是21和 CTFontRef .448对于相同的字体?有什么不对劲。

三个问题:

  1. “领先”真的是 kCTParagraphStyleSpecifierLineSpacingAdjustment 的意思吗?
  2. 如果是这样,我应该使用哪种方法/公式来获取它?
  3. 如果没有,我应该使用什么来调整行距?
4

2 回答 2

2

我也遇到了这个问题,这里是在一个真实项目中工作的代码:

// 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;
}
于 2013-06-28T22:12:30.127 回答
0

回答我上面的3个问题:

  1. 是的,“领先”实际上是 kCTParagraphStyleSpecifierLineSpacingAdjustment 的意思。或者无论如何,它按预期工作。
  2. 用于CTFontGetLeading(fontRef)获取字体的正常前导,或插入您选择的任何值(作为 CGFloat)。
  3. 不适用。

答案 1 和 2 有效:在属性字符串的段落样式属性中指定前导值将使 Core-Text 框架设置器能够准确计算其高度。

有两个警告:

  1. 如果您尝试增量计算高度,一次一个字符串,每个字符串包含一个初始换行符,framesetter 将认为该换行符代表一整行,而不仅仅是前导。如果您想要连接字符串的高度,则必须将该连接提供给框架设置器。当然,您可以跟踪增量的高度差,但无法避免让 framesetter 重新计算早期的字符串尺寸。
  2. CATextLayer 忽略间距调整(和其他属性)。如果按确切的字符串高度取景是个问题,您必须直接绘制到 CALayer。

还有一个谜团:UIFont 被弃用的领先是怎么回事?前导和 lineHeight 是两个不同的东西。

于 2012-04-14T17:11:28.983 回答