111

I am a UX architect working with a team of Android developers that are mostly junior. We are having issues properly setting line height in Android.

We are using the Material Design spec as our guide for our app. In particular, you can see line height specs here:

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

Let's use Body 2 as our example. The spec says the type is 13sp or 14sp, and the leading (line height - same thing) should be 24dp.

Here's the problem: these devs are telling me there is no such way to set line height like that in the code. Instead, they are telling me to measure the distance between the two lines of text and give them that measure - let's say it's 4dp. They want this for each style of text we are using.

We are using a Sketch > Zepelin flow for spec.

It seems odd to me to be able to create a font style (which could easily be class/style in the code) that is 13sp with 24dp leading, and not be able to set the leading, but instead have to add a 3rd measure to the mix. There is no place in Sketch or Zepelin for such a measure "between lines."

Is this really the way it is done, or is there a proper way to set line height?

MajorTom
  • 1,285
  • 2
  • 9
  • 9

9 Answers9

149

I'll explain this from Android Developer perspective.

Line height usually means text size + "padding" top/bottom.

So, if your designer write line height 19sp and text size 15sp, it means you need to have extra padding 4sp.

19sp - 15sp = 4sp.

To implement it in your layout, use lineSpacingExtra attribute.

<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"
/>

Another way to achieve line height is using scale. For example, 1.2. It means, the spacing is 120% of the text size.

In example above, the line height is 19sp and the text size is 15sp. If we translate it into scale, it become.

19/15 = 1.26

To implement it in your layout, use the lineSpacingMultiplier attribute.

<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"
/>
Community
  • 1
  • 1
aldok
  • 17,295
  • 5
  • 53
  • 64
  • 8
    I think if the text is in two or more lines, the lineSpacingExtra should be (19sp - 15sp) / 2 = 2sp. – AndroidRuntimeException Oct 30 '19 at 22:25
  • 10
    One thing I don't see mentioned here is that `lineSpacingMultipler` and `lineSpacingExtra` only manifest when the text in question appears as multiple lines on screen. You can see this is the documentation where it says *"The value will not be applied for the last line of text"* What this means for us developers is; if your line of text is only one line or less than this won't work for you. – szaske Jun 14 '21 at 17:04
56
lineHeight = height * multiplier + extra

So if you set multiplier = 0 then you can get line-height to be the same as an extra.

<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:textSize="14sp"
  android:lineSpacingMultiplier="0"
  android:lineSpacingExtra="24sp"
/>
Mladen Rakonjac
  • 9,562
  • 7
  • 42
  • 55
21

Since API 28 we now have lineHeight

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

If you are using a style don't forget to remove the app:

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

Or in code

TextView.setLineHeight(@Px int)
latsson
  • 630
  • 7
  • 8
  • 2
    what I've found is even Google's effort of setting Line Height doesn't match up to what is shown in designs (ie what HTML would have rendered to with the same config) - I have a 20sp textSize and 24dp lineHeight and the fontHeight calculated in TextView.setLineHeight() actually works out to 24sp so setLineHeight doesn't change anything – kassim Jan 03 '19 at 14:50
  • Removing **app** prefix yields an error: `Attribute is missing the namespace prefix` – IgorGanapolsky Jan 29 '19 at 01:19
  • 2
    @latsson What is the equivalent of the `app:lineHeight` on api 21 up to api 27? – Etienne Lawlor May 13 '20 at 01:50
  • @toobsco42 You can use this if you have compileSdkVersion to at least 28, which I guess you have? – latsson May 13 '20 at 06:43
  • 2
    @latsson Yes. But how would that work on API levels below 28? – Etienne Lawlor May 13 '20 at 06:45
  • 1
    @toobsco42 yes, since that is in the AppCompat library – latsson May 13 '20 at 11:21
  • make sure you use "app:lineHeight" and not "android:lineHeight" For api up to 27 - you can use android:lineSpacingMultiplier="[float]" To get this value use lineHeight/fontSize – harmanjd Oct 28 '21 at 18:37
8

Here's a way to do it programatically.

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;
}
miguel
  • 16,205
  • 4
  • 53
  • 64
2

TextViewCompat's setLineHeight method seems to be working for me regardless of the project's minimum SDK version.

val textView = binding.titleTextView // OR findViewById<TextView>(R.id.titleTextView)
val lineHeight = resources.getDimensionPixelSize(R.dimen.line_height)

TextViewCompat.setLineHeight(textView, lineHeight)
Zsolt Boldizsar
  • 2,447
  • 2
  • 27
  • 37
1

2022

This works for me pre API 28 and above:

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

Adding target api for "android:lineHeight" to make sure it doesn't override "lineHeight" seems to do the trick.

dot_cr2
  • 69
  • 1
  • 5
1

enter image description here Hello, We can add this like that: app:lineHeight="42dp"

Rajan A
  • 11
  • 1
0

Here's React Native's solution: add a span that adjusts the line height https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomLineHeightSpan.java

My design colleagues use line height excessively and its a pain that it never looks right after rending in-app.

I'll be planning on making a custom TextView class that takes an arg by XML and will post it here after.

kassim
  • 3,880
  • 3
  • 26
  • 27
  • 1
    This is **not** a link-only answer. It's an answer with a link. The answer is essentially "add a span that adjusts the line height" – Wai Ha Lee Apr 09 '19 at 11:51
0

following this answer
https://stackoverflow.com/a/52735596/8668620
and add

android:includeFontPadding="false"

too

lee
  • 1
  • 2