Android TextView setMaxLines后获取完整高度

泡在网上的日子 / 文 发表于2013-04-13 00:25 次阅读 TextView,android


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


收藏 赞 (0) 踩 (1)
上一篇:Android View坐标getLeft, getRight, getTop, getBottom解惑
1 引起疑惑 分析视图invalidate流程的过程中发现view的left, right, top, bottom跟自己理解的不一样,现在想分析一下这几个值具体的含义。 2 理解坐标,位置概念 这里涉及坐标系的概念: 坐标系在二维视图中通过X轴和Y轴两个数字为组合表示某个点的绝对坐
下一篇:Android Touch传递的一些简单规则
关于安卓中View之间的触摸事件传递的文章我已经搜集了很多篇了,在这个网站的搜索中你应该可以找到,下面的总结也许对加深理解仍然有用: 1. Touch事件是UI树形机构,由上向下传递。如果点击手机界面中的一个Button,其先传递给最外层的视图,经过层层向下传