18

I'm trying to determine the height of a TextView before it is drawn. I'm using the following code to do that:

TextView textView = (TextView) findViewById(R.id.textview);
textView.setText("TEST");
int widthSpec = MeasureSpec.makeMeasureSpec(LayoutParams.MATCH_PARENT, MeasureSpec.EXACTLY);
int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
textView.measure(widthSpec, heightSpec);
System.out.println("MeasuredHeight: " + textView.getMeasuredHeight());

The output is MeasuredHeight: 28. Nothing wrong with that.

However, when I give the TextView a long text string, so wrapping occurs, it still gives the height of a single line instead of two:

(...)
textView.setText("TESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTESTTEST");
(...)

The output is MeasuredHeight: 28, where I would expect MeasuredHeight: 56.

Why doesn't it give me the right value and how can I achieve the right value?

nhaarman
  • 98,571
  • 55
  • 246
  • 278
  • Maybe [this][1] will help you, it's almost the same problem! [1]: http://stackoverflow.com/questions/6157652/android-getmeasuredheight-returns-wrong-values – ObAt Jan 17 '13 at 19:34
  • I've tried the proposed solutions in that thread and in this one (http://stackoverflow.com/questions/4668939/viewgrouptextview-getmeasuredheight-gives-wrong-value-is-smaller-than-real), but they have the same result. – nhaarman Jan 17 '13 at 19:42
  • Where exactly did you used that code? – user Jan 17 '13 at 20:02
  • This is in the `onCreate()` method. – nhaarman Jan 17 '13 at 20:09
  • Try posting(with `post`) a `Runnable` on one of your views(in the `onCreate` method) and place your current code in there. – user Jan 17 '13 at 20:15
  • It still gives me the `28` value. – nhaarman Jan 17 '13 at 20:23
  • did you tried `measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)`? – sherpya May 21 '13 at 23:58

3 Answers3

10

This is a onCreate method. Your whole view hierarchy isn't measured and layouted yet. So textView's parent doesn't know it's width. That is why textView's dimentions isn't constrained by it's parent's dimentions.

Try to change your line to:

int widthSpec = MeasureSpec.makeMeasureSpec(200, MeasureSpec.EXACTLY);

so it make your textview width equals 200 pixels.

If you explain why do you need textview's height maybe we will be able to help you.

Leonidos
  • 10,482
  • 2
  • 28
  • 37
  • Well now it does give a height >28, but obviously the `TextView` is not 200px wide. – nhaarman Jan 17 '13 at 20:44
  • 1
    I need to know the height of the `TextView` to create an expanding animation. Particularly, I'm expanding a `ViewGroup` which contains multiple components. For the animation I need to know the height to animate to. At first, the `ViewGroup` is `GONE`, I set the height to `0`, set the visibility to `VISIBLE`, and increment the height gradually to the measured height. – nhaarman Jan 17 '13 at 20:46
  • @Niek: Do you know the available width for the `TextView`? Is it perhaps matching the window width? – Matthias Robbers Jan 17 '13 at 20:50
  • No. There is an ImageView next to it, and several layers of margins. – nhaarman Jan 17 '13 at 20:51
  • So ask your ViewGroup to measure itself. When you start your animation all other views are on the screen. You should know ViewGroup's available width at that time, so you can mesuare it's overall height. – Leonidos Jan 17 '13 at 21:01
  • When I measure the `ViewGroup`s height, I get a much smaller value than expected, because of the wrapping in the `TextView`s. Also, the `ViewGroup` is `GONE`, so the height and width are both 0. – nhaarman Jan 17 '13 at 21:12
  • the is no universal solution I can give you. Sometimes I override measure and layout or even onDraw methods to do some tricks there. The thing is, you should specify correct params to measure method if you want to call it manually. If you can't - find another way that depends on what you are going to do... Usually expanding view has a container which limits it's width. So right before animation is going to start I take container's width, measure expanding view's max height and animate it from 0 to maxHeight. – Leonidos Jan 17 '13 at 21:40
  • 1
    I've done some experimenting, and estimated the container's width. Now the measured height does show the right value. Thanks! – nhaarman Jan 17 '13 at 22:10
  • @nhaarman hey can you help us on how did you manage to find the right value of the measured height ? – Arvin Apr 10 '17 at 09:45
4

Yeah, I recently bumped into this one myself. The best way is to create a ViewTreeObserver object and register a ViewTreeObserver.OnGlobalLayoutListener. This will be called after the layout phase and before the draw phase. You'll be able to get the size of your TextView at that point.

That won't strictly-speaking be the text itself, but for the entire TextView. If there's internal padding involved, the actual text will be smaller than the TextView.

If you really need the dimensions of the actual text, use textView.getLayout() to get the Layout object for the text, and then use layout.getHeight().

Edward Falk
  • 9,991
  • 11
  • 77
  • 112
  • I can't use the `OnGlobalLayoutListener` for various reasons. For one, I need to measure the height of a `TextView` that has visibility `GONE` at a random point in time after the rest of the layout is drawn. – nhaarman Jan 17 '13 at 20:37
0

You have to create Custom Textview and use it in your layouts and use getActual height function to set the height at runtime

 public class TextViewHeightPlus extends TextView {
    private static final String TAG = "TextViewHeightPlus";
    private int actualHeight=0;


    public int getActualHeight() {
        return actualHeight;
    }

    public TextViewHeightPlus(Context context) {
        super(context);
    }

    public TextViewHeightPlus(Context context, AttributeSet attrs) {
        super(context, attrs);
        setCustomFont(context, attrs);
    }

    public TextViewHeightPlus(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

    }

   @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        actualHeight=0;

        actualHeight=(int) ((getLineCount()-1)*getTextSize());

    }

}
Pramod
  • 1,123
  • 2
  • 12
  • 33