Android Layout: meaning of getLineBaseline, getLineDescent, getLineAscent, getLineBottom, getLineTop

1.2k Views Asked by At

The documentation for the following methods of Layout (including StaticLayout, DynamicLayout, and BoringLayout) are very sparce.

Exactly what are the numbers that these methods are returning? Are they the normal font metrics values or are they the locations on the layout?

I made a test project to find out so I am posting my answer below Q&A style.

1

There are 1 best solutions below

0
On BEST ANSWER

I have previously described the meaning of top, ascent, baseline, descent, bottom, and leading in Android's FontMetrics.

Because the Layout methods getLineBaseline, getLineDescent, getLineAscent, getLineBottom, and getLineTop sound so similar to the FontMetrics names, it is easy to get them confused. However, they report two different types of things:

These methods return their vertical positions on the layout, which is different for every line.

  • getLineBaseline
  • getLineBottom
  • getLineTop

However, the following two methods return the value for the particular line they are on, regardless of where the line is in the layout. So unless there are special spans that affect the size, they will be the same for every line.

  • getLineAscent
  • getLineDescent

Demo

I made a simple project to demonstrate that the imformation above. There are six lines of text in an EditText. Clicking the button logs the info for each line.

enter image description here

Results

Here is the logged result:

line 0 baseline: 67
line 1 baseline: 140
line 2 baseline: 213
line 3 baseline: 286
line 4 baseline: 359
line 5 baseline: 432

line 0 descent: 15
line 1 descent: 15
line 2 descent: 15
line 3 descent: 15
line 4 descent: 15
line 5 descent: 18

line 0 ascent: -67
line 1 ascent: -58
line 2 ascent: -58
line 3 ascent: -58
line 4 ascent: -58
line 5 ascent: -58

line 0 top: 0
line 1 top: 82
line 2 top: 155
line 3 top: 228
line 4 top: 301
line 5 top: 374

line 0 bottom: 82
line 1 bottom: 155
line 2 bottom: 228
line 3 bottom: 301
line 4 bottom: 374
line 5 bottom: 450

FontMetrics top: -67
FontMetrics bottom: 18
FontMetrics ascent: -58
FontMetrics descent: 15

As you can see, top, bottom, and baseline are cumulative based on the line. Ascent and descent mainly stay the same for each line. Ascent is equal to FontMetrics.ascent for all lines except the first line, where it equals FontMetrics.top. And descent is equal to FontMetrics.descent for all lines except the last line, where it equals FontMetrics.bottom.

So top, bottom, baseline, ascent, and descent for a line should not be considered to be equal to the FontMetrics values of the same names. On a line ascent is the distance from the baseline to the bottom of the line above it. Descent is the distance from the baseline to the top of the next line.

In the source code, only top and descent are saved for every line. The other values are calculated from them:

  • bottom = top of next line
  • baseline = bottom - descent
  • ascent = top - (bottom - descent)

Project code:

public class MainActivity extends AppCompatActivity {

    EditText editText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editText = (EditText) findViewById(R.id.editText);
    }

    public void buttonClick(View view) {

        Layout layout = editText.getLayout();
        for (int i = 0; i < layout.getLineCount(); i++) {
            int baseline = layout.getLineBaseline(i);
            Log.i("TAG", "line " + i + " baseline: " + baseline);
        }
        for (int i = 0; i < layout.getLineCount(); i++) {
            int descent = layout.getLineDescent(i);
            Log.i("TAG", "line " + i + " descent: " + descent);
        }
        for (int i = 0; i < layout.getLineCount(); i++) {
            int ascent = layout.getLineAscent(i);
            Log.i("TAG", "line " + i + " ascent: " + ascent);
        }
        for (int i = 0; i < layout.getLineCount(); i++) {
            int top = layout.getLineTop(i);
            Log.i("TAG", "line " + i + " top: " + top);
        }
        for (int i = 0; i < layout.getLineCount(); i++) {
            int bottom = layout.getLineBottom(i);
            Log.i("TAG", "line " + i + " bottom: " + bottom);
        }

        Paint.FontMetricsInt fm = editText.getLayout().getPaint().getFontMetricsInt();
        Log.i("TAG", "fm top: " + fm.top);
        Log.i("TAG", "fm bottom: " + fm.bottom);
        Log.i("TAG", "fm ascent: " + fm.ascent);
        Log.i("TAG", "fm descent: " + fm.descent);
    }
}

See also