如何正确设置Android的行高?

112

我是一名UX架构师,与一支主要由初级Android开发人员组成的团队合作。我们在Android中设置行高遇到了问题。

我们使用Material Design规范作为应用程序的指南。特别地,您可以在此处查看行高规范:

https://material.google.com/style/typography.html#typography-line-height

让我们以Body 2作为例子。规范说明类型为13sp或14sp,行距(行高-同样的东西)应为24dp。

问题来了:这些开发人员告诉我没有办法像代码中那样设置行高。相反,他们要求我测量文本两行之间的距离并给予该值--假设它是4dp。他们想要我们对使用每个文本样式进行此操作。

我们正在使用Sketch > Zepelin流程进行设计规范。

对我来说,似乎很奇怪能够创建一个字体样式(可以轻松成为代码中的类/样式),其大小为13sp,领先为24dp,但无法设置导线,而必须添加第三个测量值。在Sketch或Zepelin中没有这样的“行间距”测量。

这是真正的做法,还是有正确的设置行高的方法?


1
使用 lineSpacingMultiplier 为零是一个绝妙的解决方案,下面是 @MladenRakonjac 的建议! - Fattie
9个回答

150

从Android开发者的角度来解释这个问题。

通常情况下,行高指的是文本大小+上下方向上的"填充"。

因此,如果你的设计师设置了行高为19sp,文本大小为15sp,这意味着你需要额外添加4sp的填充。

19sp - 15sp = 4sp。

要在布局中实现它,请使用lineSpacingExtra属性。

<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:textSize="15sp"
  android:lineSpacingExtra="4sp"
  android:fontFamily="sans-serif"
  tools:text="StackOverflow is awesome"
/>

实现行高的另一种方法是使用比例尺。例如,1.2。这意味着,行距是文本大小的120%。

在上面的示例中,行高为19sp,文本大小为15sp。如果我们将其转换为比例尺,则变为:

19/15 = 1.26

要在布局中实现它,请使用lineSpacingMultiplier属性。

<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:textSize="15sp"
  android:lineSpacingMultiplier="1.26"
  android:fontFamily="sans-serif"
  tools:text="StackOverflow is awesome"
/>

8
我认为如果文本跨越两行或更多行,行间距应为(19sp - 15sp)/ 2 = 2sp。 - AndroidRuntimeException
11
这里没有提到的一件事是lineSpacingMultiplerlineSpacingExtra只有在所讨论的文本在屏幕上显示为多行时才会显现。您可以在文档中看到这一点,其中写道:"该值不会应用于文本的最后一行"对于开发人员来说,这意味着:如果您的文本只有一行或少于一行,那么这将对您无效。 - szaske

56
lineHeight = height * multiplier + extra

如果您将 multiplier = 0,则可以使行高与额外行高相同。

<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:textSize="14sp"
  android:lineSpacingMultiplier="0"
  android:lineSpacingExtra="24sp"
/>

这绝对是最好的向后兼容和可靠的解决方案。 - NoHarmDan
8
缺点是这种方法无法用于单行。 - Ionut Negru

21

自API 28以来,我们现在拥有了lineHeight

<TextView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="Lorem ipsum dolor sit amet"
app:lineHeight="50sp"/>

如果您使用了样式,请不要忘记移除该应用程序:

<style name="H1">
    <item name="android:textSize">20sp</item>
    <item name="lineHeight">30sp</item>
</style>

或者在代码中

TextView.setLineHeight(@Px int)

2
我发现即使是谷歌设置行高的努力也无法与设计中显示的内容相匹配(即使用相同配置呈现HTML的内容)- 我有一个20sp的文本大小和24dp的行高,而在TextView.setLineHeight()中计算出的字体高度实际上是24sp,因此setLineHeight不会改变任何东西。 - kassim
2
@latsson 在 API 21 到 API 27 上,app:lineHeight 的等效属性是什么? - Etienne Lawlor
2
@latsson 是的。但是在 API 级别低于 28 的情况下,这将如何工作? - Etienne Lawlor
1
@toobsco42 是的,因为它在AppCompat库中。 - latsson
请使用“app:lineHeight”而不是“android:lineHeight”。对于API版本27及以下,您可以使用android:lineSpacingMultiplier="[float]"。要获取此值,请使用lineHeight/fontSize。 - harmanjd
显示剩余2条评论

8

这里有一种以编程方式实现的方法。

public static void setLineHeight(TextView textView, int lineHeight) {
    int fontHeight = textView.getPaint().getFontMetricsInt(null);
    textView.setLineSpacing(dpToPixel(lineHeight) - fontHeight, 1);
}

public static int dpToPixel(float dp) {
    DisplayMetrics metrics = getResources().getDisplayMetrics();
    float px = dp * (metrics.densityDpi / 160f);
    return (int) px;
}

2

不要将代码作为图像添加,应该将其作为文本添加在代码块中(三个反引号(```))。 - SimonC

2
TextViewCompatsetLineHeight方法似乎对我来说是有效的,无论项目的最低SDK版本是什么。
val textView = binding.titleTextView // OR findViewById<TextView>(R.id.titleTextView)
val lineHeight = resources.getDimensionPixelSize(R.dimen.line_height)

TextViewCompat.setLineHeight(textView, lineHeight)

1

2022年

在API 28及以上版本之前,以下方法适用:

<style name="whatever">
    <item name="android:lineHeight" tools:targetApi="p">28sp</item>
    <item name="lineHeight">28sp</item>
</style>

添加目标API以针对“android:lineHeight”,以确保它不会覆盖“lineHeight”,似乎是解决问题的方法。


0

1
这不是仅有链接的答案,而是一个带有链接的答案。本质上,答案是“添加一个调整行高的span”。 - Wai Ha Lee

0

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