Android TextView setMaxLines后获取完整高度
TextView设置完setMaxLines后,通过TextView.getHeight方法获取的是当前行数的高度,而非文字完全显示的高度。
以下左边的图是《选择》这首诗一共只显示5行,右侧的图片中可以看到5行文字的高度,但是此时获取不到完整显示时TextView的高度
textView.setMaxLines(5);
textView.getHeight(); // 125
获取TextView的完整高度,核心代码
private int getTextViewHeight(TextView pTextView) {
Layout layout = pTextView.getLayout();
int desired = layout.getLineTop(pTextView.getLineCount());
int padding = pTextView.getCompoundPaddingTop() + pTextView.getCompoundPaddingBottom();
return desired + padding;
}
完整代码
public class MainActivity extends Activity {
private static final String value = "选 择 汪国真\\n你的路\\n已经走了很长很长\\n走了很长"
+ "\\n可还是看不到风光\\n你的心很苦\\n很彷徨\\n没有风帆的船\\n不比死了强\\n没有罗盘的风帆"
+"\\n只能四处去流浪\\n如果你是鱼不要迷恋天空\\n如果你是鸟不要痴情海洋";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView output = (TextView) findViewById(R.id.output);
output.setText("在屏幕上点击,可以获取输出TextView高度信息");
final TextView textView = (TextView) findViewById(R.id.textview);
textView.setText( value );
textView.setMaxLines(5);
RelativeLayout layout = (RelativeLayout) findViewById(R.id.layout);
layout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("当前TextView设置setMaxLines属性未全部显示\\n");
stringBuilder.append("textView.getHeight = ");
stringBuilder.append( textView.getHeight() );
stringBuilder.append("\\n");
stringBuilder.append("TextView全部文字显示的实际高度: ");
stringBuilder.append(getTextViewHeight(textView));
output.setText( stringBuilder.toString() );
textView.setMaxLines(Integer.MAX_VALUE);
}
});
}
private int getTextViewHeight(TextView pTextView) {
Layout layout = pTextView.getLayout();
int desired = layout.getLineTop(pTextView.getLineCount());
int padding = pTextView.getCompoundPaddingTop() + pTextView.getCompoundPaddingBottom();
return desired + padding;
}
}
通过阅读TextView源码,查找其TextView宽高的计算方式,首先看TextView.onMeasure方法,TextView继承自View,View都是通过在onMeasure方法中确定宽高的。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 宽度相关代码不看,此处此关心与高度相关的
......
// 高度
if (heightMode == MeasureSpec.EXACTLY) {
// Parent has told us how big to be. So be it.
height = heightSize;
mDesiredHeightAtMeasure = -1;
} else {
// 从这里获取的TextView高度
int desired = getDesiredHeight();
height = desired;
mDesiredHeightAtMeasure = desired;
if (heightMode == MeasureSpec.AT_MOST) {
height = Math.min(desired, heightSize);
}
}
// 没有填充的高度
int unpaddedHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom();
if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) {
unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum));
}
/*
* We didn't let makeNewLayout() register to bring the cursor into view,
* so do it here if there is any possibility that it is needed.
*/
if (mMovement != null ||
mLayout.getWidth() > unpaddedWidth ||
mLayout.getHeight() > unpaddedHeight) {
registerForPreDraw();
} else {
scrollTo(0, 0);
}
setMeasuredDimension(width, height);
}
从上面代码中可以获取到,高度是通过此TextView.getDesiredHeight获得,接着查看这段代码
private int getDesiredHeight(Layout layout, boolean cap) {
if (layout == null) {
return 0;
}
// 行数
int linecount = layout.getLineCount();
// padding
int pad = getCompoundPaddingTop() + getCompoundPaddingBottom();
// 期望值
int desired = layout.getLineTop(linecount);
final Drawables dr = mDrawables;
if (dr != null) {
desired = Math.max(desired, dr.mDrawableHeightLeft);
desired = Math.max(desired, dr.mDrawableHeightRight);
}
desired += pad;
if (mMaxMode == LINES) {
/*
* Don't cap the hint to a certain number of lines.
* (Do cap it, though, if we have a maximum pixel height.)
*/
if (cap) {
if (linecount > mMaximum) {
desired = layout.getLineTop(mMaximum) +
layout.getBottomPadding();
if (dr != null) {
desired = Math.max(desired, dr.mDrawableHeightLeft);
desired = Math.max(desired, dr.mDrawableHeightRight);
}
desired += pad;
linecount = mMaximum;
}
}
} else {
desired = Math.min(desired, mMaximum);
}
if (mMinMode == LINES) {
if (linecount < mMinimum) {
desired += getLineHeight() * (mMinimum - linecount);
}
} else {
desired = Math.max(desired, mMinimum);
}
// Check against our minimum height
desired = Math.max(desired, getSuggestedMinimumHeight());
return desired;
}