The documentation for the following methods of Layout
(including StaticLayout
, DynamicLayout
, and BoringLayout
) are very sparce.
getLineBaseline(int line)
getLineDescent(int line)
getLineAscent(int line)
getLineBottom(int line)
getLineTop(int line)
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.
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
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.
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:
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);
}
}