[ACCEPTED]-How to retrieve the dimensions of a view?-measure

Accepted answer
Score: 419

I believe the OP is long gone, but in case 12 this answer is able to help future searchers, I 11 thought I'd post a solution that I have 10 found. I have added this code into my onCreate() method:

EDITED: 07/05/11 9 to include code from comments:

final TextView tv = (TextView)findViewById(R.id.image_test);
ViewTreeObserver vto = tv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        LayerDrawable ld = (LayerDrawable)tv.getBackground();
        ld.setLayerInset(1, 0, tv.getHeight() / 2, 0, 0);
        ViewTreeObserver obs = tv.getViewTreeObserver();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            obs.removeOnGlobalLayoutListener(this);
        } else {
            obs.removeGlobalOnLayoutListener(this);
        }
    }

});

First I get 8 a final reference to my TextView (to access in the 7 onGlobalLayout() method). Next, I get the ViewTreeObserver from my TextView, and 6 add an OnGlobalLayoutListener, overriding onGLobalLayout (there does not seem 5 to be a superclass method to invoke here...) and 4 adding my code which requires knowing the 3 measurements of the view into this listener. All 2 works as expected for me, so I hope that 1 this is able to help.

Score: 84

I'll just add an alternative solution, override 3 your activity's onWindowFocusChanged method 2 and you will be able to get the values of 1 getHeight(), getWidth() from there.

@Override
public void onWindowFocusChanged (boolean hasFocus) {
        // the height will be set at this point
        int height = myEverySoTallView.getMeasuredHeight(); 
}
Score: 20

You are trying to get width and height of 18 an elements, that weren't drawn yet.

If you 17 use debug and stop at some point, you'll 16 see, that your device screen is still empty, that's 15 because your elements weren't drawn yet, so 14 you can't get width and height of something, that 13 doesn't yet exist.

And, I might be wrong, but 12 setWidth() is not always respected, Layout lays out it's 11 children and decides how to measure them 10 (calling child.measure()), so If you set setWidth(), you are not 9 guaranteed to get this width after element 8 will be drawn.

What you need, is to use getMeasuredWidth() (the 7 most recent measure of your View) somewhere 6 after the view was actually drawn.

Look into 5 Activity lifecycle for finding the best moment.

http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

I 4 believe a good practice is to use OnGlobalLayoutListener like 3 this:

yourView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (!mMeasured) {
                // Here your view is already layed out and measured for the first time
                mMeasured = true; // Some optional flag to mark, that we already got the sizes
            }
        }
    });

You can place this code directly in 2 onCreate(), and it will be invoked when views will 1 be laid out.

Score: 16

Use the View's post method like this

post(new Runnable() {   
    @Override
    public void run() {
        Log.d(TAG, "width " + MyView.this.getMeasuredWidth());
        }
    });

0

Score: 7

I tried to use onGlobalLayout() to do some custom formatting 11 of a TextView, but as @George Bailey noticed, onGlobalLayout() is 10 indeed called twice: once on the initial 9 layout path, and second time after modifying 8 the text.

View.onSizeChanged() works better for me because if 7 I modify the text there, the method is called 6 only once (during the layout pass). This 5 required sub-classing of TextView, but on API Level 4 11+ View. addOnLayoutChangeListener() can be used to avoid sub-classing.

One 3 more thing, in order to get correct width 2 of the view in View.onSizeChanged(), the layout_width should be set to match_parent, not 1 wrap_content.

Score: 2

Are you trying to get sizes in a constructor, or 8 any other method that is run BEFORE you 7 get the actual picture?

You won't be getting 6 any dimensions before all components are 5 actually measured (since your xml doesn't 4 know about your display size, parents positions 3 and whatever)

Try getting values after onSizeChanged() (though 2 it can be called with zero), or just simply 1 waiting when you'll get an actual image.

Score: 2

I guess this is what you need to look at: use 3 onSizeChanged() of your view. Here is an EXTENDED code 2 snippet on how to use onSizeChanged() to get your layout's 1 or view's height and width dynamically http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions.html

Score: 2

As F.X. mentioned, you can use an OnLayoutChangeListener to the 3 view that you want to track itself

view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        // Make changes
    }
});

You can 2 remove the listener in the callback if you 1 only want the initial layout.

Score: 1

ViewTreeObserver and onWindowFocusChanged() are not so necessary at all.

If you 14 inflate the TextView as layout and/or put some content 13 in it and set LayoutParams then you can use getMeasuredHeight() and getMeasuredWidth().

BUT you 12 have to be careful with LinearLayouts (maybe also other ViewGroups). The issue 11 there is, that you can get the width and 10 height after onWindowFocusChanged() but if you try to add some 9 views in it, then you can't get that information 8 until everything have been drawn. I was 7 trying to add multiple TextViews to LinearLayouts to mimic a FlowLayout (wrapping 6 style) and so couldn't use Listeners. Once the process 5 is started, it should continue synchronously. So 4 in such case, you might want to keep the 3 width in a variable to use it later, as 2 during adding views to layout, you might 1 need it.

Score: 1

Even though the proposed solution works, it 11 might not be the best solution for every 10 case because based on the documentation 9 for ViewTreeObserver.OnGlobalLayoutListener

Interface definition for a callback 8 to be invoked when the global layout state 7 or the visibility of views within the view 6 tree changes.

which means it gets called 5 many times and not always the view is measured 4 (it has its height and width determined)

An 3 alternative is to use ViewTreeObserver.OnPreDrawListener which gets called 2 only when the view is ready to be drawn 1 and has all of its measurements.

final TextView tv = (TextView)findViewById(R.id.image_test);
ViewTreeObserver vto = tv.getViewTreeObserver();
vto.addOnPreDrawListener(new OnPreDrawListener() {

    @Override
    public void onPreDraw() {
        tv.getViewTreeObserver().removeOnPreDrawListener(this);
        // Your view will have valid height and width at this point
        tv.getHeight();
        tv.getWidth();
    }

});
Score: 1

Height and width are zero because view has 4 not been created by the time you are requesting 3 it's height and width . One simplest solution 2 is

view.post(new Runnable() {
    @Override
    public void run() {
        view.getHeight(); //height is ready
        view.getWidth(); //width is ready
    }
});

This method is good as compared to other 1 methods as it is short and crisp.

Score: 0

You should rather look at View lifecycle: http://developer.android.com/reference/android/view/View.html Generally 3 you should not know width and height for 2 sure until your activity comes to onResume 1 state.

Score: 0

You can use a broadcast that is called in 4 OnResume ()

For example:

int vh = 0;   
int vw = 0;

public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.maindemo);  //<- includes the grid called "board"

      registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                TableLayout tl = (TableLayout) findViewById(R.id.board);  
                tl = (TableLayout) findViewById(R.id.board);
                vh = tl.getHeight();       
                vw = tl.getWidth();               
            }
      }, new IntentFilter("Test"));
}

protected void onResume() {
        super.onResume();

        Intent it = new Intent("Test");
        sendBroadcast(it);

}

You can not get the 3 height of a view in OnCreate (), onStart 2 (), or even in onResume () for the reason 1 that kcoppock responded

More Related questions