How to get an Android widget's size after layout is calculated?

Randy Sugianto 'Yuku' picture Randy Sugianto 'Yuku' · May 19, 2010 · Viewed 20.5k times · Source

I have a layout which specifies sizes of widgets in relative dimension, for example:

<LinearLayout ... layout_height="fill_parent">
     <ImageView ... layout_height="wrap_content" />
     <TextView ... layout_height="120dp" />
</LinearLayout>

Immediately after onCreate, I want to know how much is the height of the ImageView. How to do that?

Note: If I call getHeight() in onCreate, I get 0.

I have also tried imageView.postDelayed, it works on 2.1 emulator but fails on 1.5 emulator (I got 0, too).

Finally, I tried to create a Handler, and then I call handler.postDelayed with 10 ms delay. It works in both 2.1 and 1.5 emulator, but failed when I start the program in eclipse debugger (So, I conclude that using the delay doesn't guarantee that the getting of the height happens after the imageview is layout-ted.)

Answer

Steve Haley picture Steve Haley · May 19, 2010

The reason you're getting a size of 0 is that the layout isn't finished until after the activity is fully created, i.e. onCreate(), onStart() and onResume() have all gone through. The easiest way I know of to get the exact size is to call your method after the layout has finished, such as by using a click listener on a button. Since the button isn't displayed until the layout is finished, the size must be available by the time its click listener is fired.

This is only a guess, but I imagine that this is difficult to do precisely because they don't want people messing with layout sizes once the system has just finished laying out the screen. If they provided a "onLayoutFinished()" callback, then you could get yourself stuck in a loop if you modified the layout in that. For example, imagine: layout is completed; onLayoutFinished() called and you modify the layout in there; the existing layout is now invalid; layout re-done; onLayoutFinished() called again; your code gets called again - and so forth.

Another way to do it is to make a custom View and override the onMeasure(int, int) method. The system triggers that method to get the size of each View; if you use something like my example below, you can get the suggested size before the layout is finished:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //getMeasuredHeight() and getMeasuredWidth() now contain the suggested size
}

(I wrote that it's the suggested size because I think it's possible for the size to be changed after this based on layout constraints. However, that's a vague memory of something I read a while ago, and I never experimented in detail.) Once you've done that, you can use the size for whatever it is you wanted to do - you can even change the size it will use by using setMeasuredDimension(newX, newY).