4

Simple question, perhaps frustratingly-complex-but-hopefully-simple answer?

What is the "Best Practice" for getting the actual height of an element that has its size set to FILL_PARENT?

Cristian
  • 198,401
  • 62
  • 356
  • 264
Wonko the Sane
  • 10,623
  • 8
  • 67
  • 92
  • 2
    This is probably a duplicate of this SO question: http://stackoverflow.com/questions/2864331/how-to-get-an-android-widgets-size-after-layout-is-calculated – Yoni Samlan Dec 21 '10 at 17:04
  • Thank you - my search fu has already left for the holiday. I am going to try the answer below first, but it is good to have options. – Wonko the Sane Dec 21 '10 at 18:22

2 Answers2

17

Definitely is more complicated than it seems it should be. An easier way that I've found compared to the answer in the suggested question, is to use a ViewTreeObserver. In your onCreate() method, you can use some code such as the following:

TextView textView = (TextView)findViewById(R.id.my_textview);
ViewTreeObserver observer = textView.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        //in here, place the code that requires you to know the dimensions.
        //this will be called as the layout is finished, prior to displaying.
    }
});
Abandoned Cart
  • 4,512
  • 1
  • 34
  • 41
Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • Works for me - thanks. The only caveat is that you need to take care to catch the fact that you've gone into the event one time (or only as needed) - otherwise, you'll end up in an endless layout loop. – Wonko the Sane Dec 21 '10 at 19:56
  • Could you explain more what you mean by that? I don't exactly understand. Wouldn't it only be called during onCreate() or onResume() a single time? – Kevin Coppock Dec 21 '10 at 20:00
  • (Sorry for the delay - Christmas break) No - you are creating an event handler, so it will be called any time the layout changes. If you don't have a flag that says "I've made my necessary layout changes" it will call it again when you've made your change, and again after that change is made, and... – Wonko the Sane Dec 28 '10 at 15:13
  • So you'd only end up in a loop if you actually modified something in the layout, then? So you could have onGlobalLayout modify another variable, then just remove the OnGlobalLayoutListener afterward? (Interesting note: in the ViewTreeObserver documentation, the method to remove seems to be mistakenly named removeGlobalOnLayoutListener instead of removeOnGlobalLayoutListener.) – Kevin Coppock Dec 28 '10 at 18:36
  • @kcoppock both methods exist, but one is deprecated and one is unavailable before API 16. It looks like they decided to change the method name ... http://developer.android.com/reference/android/view/ViewTreeObserver.html#removeGlobalOnLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener) – Andrew Wyld Mar 01 '13 at 16:49
  • 1
    Oh, wait, I just realized you probably wrote this *before* API 16. Well *now* both methods exist! I guess they noticed the discrepancy between the API and the documentation and decided the API was wrong! – Andrew Wyld Mar 01 '13 at 16:52
  • @AndrewWyld Haha yeah, I almost wish they wouldn't have; now we have to deal with the deprecation warning when we use it. >.> – Kevin Coppock Mar 01 '13 at 16:55
2

Just an extra amendment to the above answer, if you need to perform any operations to dimensions of multiple components in a view. The layout listener is called for each view as its layout completes. This is recursively true up to the root view component (i.e. child elements generate layout events, then the parent element generates its layout event). What this means is that you can simply hook onto the root view component's layout event to be notified when any view's layout changes.

ViewTreeObserver observer = this.findViewById(android.R.id.content).getViewTreeObserver();

Now you can expect that all your views will have width and height values set in onGlobalLayout because they've all performed their layout. This is obviously preferable to creating many listeners for each view that needs to expose its actual dimensions (unless of course you absolutely must have scope for which view generated the event, which is typically not necessary).

pjs
  • 2,601
  • 1
  • 20
  • 24
  • Also make sure you are not measuring dimensions for elements in visibility="gone" state. Or you may find out that recursiveness is "not working" – Nikolay R Apr 02 '15 at 13:16