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; }