为Framesetter提供正确的行间距调整

时间:2012-04-08 23:23:50

标签: ios objective-c uifont ctfontref

有几篇帖子指出从CTFramesetterSuggestFrameSizeSithWithConstraints中获取精确高度的困难,在这里,(framesetter post),@ Chris DeSalvo给出了看似确定的修正:使用正确的行间距调整添加段落样式设置。 / p>

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 - ascender + descender

以下是其他一些UIFont值:

  • 21.000 UIFont的lineHeight
  • 15.232 UIFont的ascender(Y coord from baseline)
  • -3.408 UIFont的下行(Y coord from baseline)
  • 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(类ref表示“根据字体引用的点大小和矩阵缩放的缩放字体 - 下降度量” - 这显然意味着它是从基线开始的Y坐标的绝对值?)

我注意到UIFont以前有一个专门用于“领先”的属性,但它已被弃用,我们建议使用lineHeight代替。因此,对于相同的字体,UIFont认为导致 21 和CTFontRef .448 ?有些事情不对。

三个问题:

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

2 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:0)

我上面提到的3个问题的答案:

  1. 是的,“领先”真正意味着kCTParagraphStyleSpecifierLineSpacingAdjustment。或者无论如何,它按预期工作。
  2. 使用CTFontGetLeading(fontRef)获取字体的正常值,或插入您选择的任何值(作为CGFloat)。
  3. N / A。
  4. 答案1和2有效:指定属性字符串的paragraphStyle属性中的前导值将使Core-Text框架集能够计算其高度完全

    有两点需要注意:

    1. 如果您尝试逐步计算高度,一次一个字符串,每个字符串包含一个初始换行符,framesetter会将该换行符视为整行,而不仅仅是前导。如果需要连接字符串的高度,则必须将该连接提供给框架设置器。当然,您可以跟踪增量高度差异,但是没有办法避免让framesetter重新计算早期的字符串尺寸。
    2. CATextLayer忽略间距调整(和其他属性)。如果确定每个精确的弦高是一个问题,则必须直接绘制到CALayer。
    3. 还有一个谜团:UIFont被弃用的领导是怎么回事?领先和lineHeight是两个不同的东西。