Android中FontMetrics的top、ascent、baseline、descent、bottom和leading的含义是什么?

113
这似乎是一个基础问题,但我在stackoverflow上找不到类似的问题。在阅读文档时,我很难理解其中的概念。我想了解topascent之间的区别以及bottomdescent之间的区别。基线究竟在哪里?你有一张图能帮助我形象化地理解吗?
2个回答

368

首先让我们回顾一下文档中的内容:

  • Top - 给定文本大小字体中最高字形距离基线的最大距离。
  • Ascent - 建议单倍行距文本的基线上方距离。
  • Descent - 建议单倍行距文本的基线下方距离。
  • Bottom - 给定文本大小字体中最低字形距离基线的最大距离。
  • Leading - 建议在文本行之间添加的额外空间。

请注意,Baseline 是从这四个指标中测量的。它是线,形成文本所在的基准线,即使某些字符(如 g、y、j 等)可能有部分在该线下方。它类似于你在线条笔记本上写的线。

以下图片可帮助您更好地理解这些内容:

FontMetrics showing top, ascent, baseline, decent, bottom, and leading

请记住,在Java和Android中绘制画布时,向下是y的增加,向上是y的减少。这意味着FontMetrics的顶部和上升是负数,因为它们是从基线测量的(而下降和底部是正数)。因此,要获取从顶部到底部的距离,您需要执行(bottom - top)。

Leading是指一行文字底部到下一行文字顶部之间的距离。在上面的图片中,它是第1行橙色和第2行紫色之间的空间。正如@MajorTom所注明的,排版术语更准确地定义为“连续排列的文本基线之间的距离。”* 然而,Android似乎更多地使用历史意义上的术语。这个词(发音为“ledding”)来自于旧的排字工人在排版时放置在文本行之间的铅条。它基本上只是一种调整行间距的方法。在Android中,我从未看过行间距不是0,也没有在源代码中看到它被用于任何事情。(如果您知道它用于计算任何内容,请纠正我。)您可以在代码中使用setLineSpacing或在xml中使用android:lineSpacingExtraandroid:lineSpacingMultiplier来更改TextView的行间距。然而, 这些方法并不使用或修改leading。

查看以下链接以获取更多信息:

了解更多

为了更深入地探索字体度量,我制作了一个简单的项目。

enter image description here

不要在这里列出所有代码。我已经将项目添加到GitHub。您可以克隆该项目,或将以下文件复制到新项目中。

字母会超过top或低于bottom吗?

通常不会,但是它们可能会。据我所知,顶部和底部是由字体设定的(因此称为“FontMetrics”),因此字体制造商可以使字形比其所说的顶部更高(或低于底部)。此外,在Unicode中使用combining diacritical marks非常容易发生。这是一个相当极端的例子(取自here):M̵̳̙͔̟̱͕̓̀̄̉̅ͧ̋͊͌͑́͌ͪ̒̿̀̚a͔̟̝͔ͥ̈́̏ͮͯ̇͆̊̒ͦͦ͘͢͜y̵̴̢͕̝̩̱͈͕̼̣͕̟̌͗̾ͤ̎͌̄ͣͨ͊ͬb̡̯̰̪̜͙̟̝̠͚̜̥̙̤̃ͨ̋̒̒̊ͧͤ͐̓͋̌̾̇̔̈́̀́͡͠e̵ͯͪ̿̿̂̄ͫ̃҉͏͎̣̹̱̜͉̦̞̪̘̠̝̝͍̼̜̖̥̭͟ ̣̞͙͚̝̰̞̹̗̲̣͙͍͍̀̓͊̂̋ͣ̏̑̍̊͌ͩ͐̎̀ͣͣ̚͟ͅh̛͋̏̍̆ͤ͛͐ͨ̌̋ͤ̎̂ͨ̂̓̑̚̕͟͏̻̣͖̖͚͚͓̲̼̪ȁ̔̅̿͐̑͡͏̝͓̮͚̘̦̰͚͎͔͉͚̮̠̕͜ͅṱ̱̼̖̓̂ͭ̏̅͂ͥ͌ͯ͌͠sͪ̓ͪ̄̌̓ͧ͋͐ͬ̅̑҉̨̪̬͎͍̥̬?̡̮̳͙͓͔̹̘̹͓̘̻̦̣͎̫̐ͤ̐͛́͝ ̧̦̼̘͕̪̠̙͖̦̯̦̘͉͈͕͔̘̻̲͑ͨ̊̈́̐ͫ͐̌ͯ̀͘͝Ḩ̷̸̸̹͉̩̜̹̞ͯ̃̃ͧͬͨ̌̀̾̐̈̇ͧ͛̃͐̀ͦ͞A̴̦̗̬̠͙̭͉̟̺͇̭̰͔͕̯̅̃͋ͪ̈́̉̓̌ͯ̈́͆̋̀ͤ̇̂̿̈́̂͡͡Ṱ̲͎͉̣̳̺̱̜̦̬͕̣͉͇͊̌ͥ͐͒̈́̓́ͥ́́̋͂̅ͬ̆͗ͥ̕。
将该字符串插入到Android中,我们得到以下结果:

enter image description here

The diacritical marks go above the top and below the bottom. It is interesting to note that the total width and height are correctly measured by the text bounds, though.
Anyway, for all practical purposes in your programming, you can just assume that the max and min for glyph letters are top and bottom. And usually they will stay within ascent and descent. If for whatever reason you need to know for sure if the letters go beyond top or bottom you can use TextPaint.getTextBounds.

不错!你知道上升、下降等是用什么单位来衡量的吗?它们是以像素为单位吗?它们是浮点值,但不确定它们如何对应屏幕。我在Photoshop中检查了它们是否为像素,并发现有一些微小的差异;像素更小一些。 - Vikram Gupta
@VikramGupta。单位为像素。我不确定是什么原因导致您的Photoshop图像有所不同,请检查。 - Suragch
感谢您提供有用的解释和应用程序。但是,您能进一步解释一下什么是“顶部”吗?是否会有任何字母高到足以触及“顶部”线?例如,“M”、“l”似乎是最高的字母。但它们都没有接触到“顶部”。 - Cheok Yan Cheng
@CheokYanCheng,请查看我回答末尾的更新。 - Suragch
@Suragch 感谢您提供的信息。我使用您的应用程序来更好地了解。我期望"Ascent"行将像您的屏幕截图一样漂亮地触及字体的顶部。然而,从最新的http://i.imgur.com/aRxgjvu.png中可以看出,它没有触及最高的字符"M"。您有任何想法吗? - Cheok Yan Cheng
@CheokYanCheng,这是我最初的预期。但请记住,“M”不一定是字体中最高的字形。即使它是特定字体中最高的字母,字体制造商也可能会为其他可能更高的字符留出空间。别忘了表情符号。我刚刚测试了表情符号,它触及了上升线和下降线。因此,通常拉丁字母实际上从未触及上升线,这使得我答案中的图片有点具有欺骗性。 - Suragch

5
Leading不是排版中行间距。显然,这是Android代码没有考虑到的事情。我们自己也在为此苦苦挣扎。Leading的正确定义(来自维基百科):在排版中,Leading /ˈlɛdɪŋ/指的是连续两行文字之间的基线距离。该术语起源于手工排版时期,当时向版面中插入薄铅条以增加排印行之间的垂直距离。

据我所知,Android没有指定此选项的方法。


+1 是为了帮助我更好地理解行距。至于更改行距,您可以在代码中使用 TextView 的 setLineSpacing,或者在 xml 中使用 android:lineSpacingExtraandroid:lineSpacingMultiplier - Suragch
谢谢 - 是的,我们被告知要使用android:lineSpacingExtra,它会在实际行间距之间放置一个测量值。这不是行距,但似乎是管理间距的唯一方法。这是一个问题,因为在排版中没有这样的测量值,并且在我们使用的Sketch或Zepelin工具中也没有指定该测量值的方法。此外,它与行距不匹配。 - MajorTom
1
如果排版行距是基线之间的距离,那么似乎应该很容易计算。 - Suragch
我已经有一段时间没有使用这个了,但如果我要重新开始,我会从这里(https://dev59.com/MnA65IYBdhLWcg3wvxaE)和这里(https://dev59.com/pG445IYBdhLWcg3wGWZ7)开始,并尝试不同的文本和字体。即使它不是很直接,我相信一定有一种方法可以计算出你需要的东西。 - Suragch
这确实是来自印刷排版的定义,但在CSS中,至少由于行间距,行间距被分为一行的顶部和底部部分,因此行高是从行框之间测量的。这比古典印刷排版更好,而在过去是不可能做到的。 - Marius
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接