在渲染之前测量多行TextView的高度

时间:2015-06-02 08:31:44

标签: java android textview

我尝试过的目标:

  1. 致电measure()

    tv.measure(0, 0);
    int height = tv.getMeasuredHeight();
    
  2. 使用指定的尺寸/模式调用measure()

    int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(99999, View.MeasureSpec.AT_MOST);
    int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    tv.measure(widthMeasureSpec, heightMeasureSpec);
    int height = tv.getMeasuredHeight();
    
  3. 致电getTextBounds()

    Rect bounds = new Rect();
    tv.getPaint().getTextBounds(tv.getText().toString(), 0, tv.getText().length(), bounds);
    int height = bounds.height();
    
  4. 致电measure(),然后致电getTextBounds()

  5. 致电getLineCount() * getLineHeight()
  6. 似乎无效。它们都返回不正确的值(容器视图的高度不正确 - 它太小或太大)

    关于如何计算这个简单事物的想法??

4 个答案:

答案 0 :(得分:1)

你在哪里打电话给那些方法? 执行您要执行的操作的最佳方法是使用ViewTreeObserver并添加onPreDrawListener。 看看this我认为它会有所帮助

答案 1 :(得分:1)

您可以在此处执行ViewTreeObserver与此TextView相关联,并向其添加OnGlobalLayoutListener:

final ViewTreeObserver vto = textView.getViewTreeObserver();

vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        // textView dimensions are calculated at this stage, but textView
        // isn't rendered yet. Do what you need to do and remove OnGlobalLayoutListener
        // after

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            textView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        } else {
            textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    }
}

答案 2 :(得分:1)

您需要指定可用的宽度,以便正确计算高度。

注意:如果您只需要获取已绘制视图的高度,请使用ViewTreeObserver。有关在这种情况下需要考虑的事项,请参阅this question

这就是为什么我在一段代码中,我希望将视图从隐藏缩放到其完整的必要高度:

int availableWidth = getParentWidth(viewToScale);

int widthSpec = View.MeasureSpec.makeMeasureSpec(availableWidth, View.MeasureSpec.AT_MOST);
int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);

viewToScale.measure(widthSpec, heightSpec);
int measuredHeight = viewToScale.getMeasuredHeight();
// Offtopic: Now I animate the height from 1 to measuredHeight (0 doesn't work)

您可以自己传递availableWidth,但我是从父母那里计算的:

private int getParentWidth(View viewToScale)
{
    final ViewParent parent = viewToScale.getParent();
    if (parent instanceof View) {
        final int parentWidth = ((View) parent).getWidth();
        if (parentWidth > 0) {
            return parentWidth;
        }
    }

    throw new IllegalStateException("View to scale must have parent with measured width");
}

答案 3 :(得分:-1)

我最近遇到了类似的问题,试图测量包含多个多行TextView的ViewGroup的高度。

对我有用的是测量()TextView,然后将(lineCount-1)* lineHeight添加到其measuredHeight。

以下是仅测量一个TextView的代码:

private int getMeasuredHeight(TextView textView) {
    textView.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
    int height = textView.getMeasuredHeight();
        height += (textView.getLineCount()-1) * textView.getLineHeight();
    return height;
}

对于具有许多TextView的ViewGroup,这是我的代码:

private int getMeasuredHeight(ViewGroup viewGroup) {
    viewGroup.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
    int height = viewGroup.getMeasuredHeight();
    for(TextView textView : findAllTextView(viewGroup)) {
        height += (textView.getLineCount()-1) * textView.getLineHeight();
    }
    return height;
}

private List<TextView> findAllTextView(ViewGroup v) {
    List<TextView> result = new ArrayList<>();
    for (int i = 0; i < v.getChildCount(); i++) {
        Object child = v.getChildAt(i);
        if (child instanceof TextView)
            result.add((TextView) child);
        else if (child instanceof ViewGroup)
            for(TextView tv: findAllTextView((ViewGroup) child))
                result.add(tv);
    }
    return result;
}