Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.)

like image 597
Randy Sugianto 'Yuku' Avatar asked May 19 '10 09:05

Randy Sugianto 'Yuku'


2 Answers

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).

like image 63
Steve Haley Avatar answered Sep 28 '22 08:09

Steve Haley


The View object provides method called onSizeChanged(int w, int h, int oldw, int oldh). It is called when the layout changes the size of one of its components. If you override this method then the the code in your version of this method will know the size of itself as shown in the following snippet.

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    bounds = new Rect();
    this.getDrawingRect(bounds);
    // bounds will now contain none zero values
}
like image 34
securelpb Avatar answered Sep 28 '22 10:09

securelpb