Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get or compute the width/height of an inflated view

Tags:

How do I compute the width and height of an inflated View if the parent is a PopupWindow, not a ViewGroup? I cannot use LayoutInflator.inflate(int resId, ViewGroup parent, attachToRoot boolean) because PopupWindow is not a ViewGroup, so I use LayoutInflator.inflate(int resId) instead, but after that I getWidth() and getHeight() return zero :(

I need to resize the PopupWindow to fit the View, but cannot do so until the View has a parent. Do I have a chicken-and-egg problem?

By the way the View is a subclass of RelativeView so calculating it manually is essentially out of the question.

Thanks in advance, Barry

like image 479
Barry Fruitman Avatar asked Jun 21 '11 18:06

Barry Fruitman


2 Answers

Actually popupWindow supports "wrap content" constans, so if you want popup be exact as your view - use this:

popup = new PopupWindow(context);
popup.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
popup.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);

--other options--

getWidth() and getHeight() returns zero, because view have size only after drawing on the screen. You can try to get values from LayoutParams of inflated view.

If there is fill_parent value - you are in egg-chicken situation.

If there is values in px or dp you can manually calculate size in pixels:

Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpSize, context.getResources().getDisplayMetrics()));

If there is wrap_content value - you can use view.measure() method - all children and view itself will be measured, and you can get view.getMeasuredHeight() and view.getMeasuredWidth().

like image 200
Jin35 Avatar answered Sep 19 '22 13:09

Jin35


As Jin35 said, your problem was that the view's width and height haven't been calculated yet...the dimensions aren't calculated until after the layout pass.

Using a fixed width and height from dimension resources (e.g. from a values/dimens.xml file) is one workaround, since then you don't need to wait for the view's onMeasure to occur -- you can get the value of the same dimension resource you used for the view you're interested in, and use that.

A better solution is to just delay your calculations until after the onMeasure happens. You can do that by overriding onMeasure, but a more elegant solution is to use a temporary OnGlobalLayoutListener like this:

View popup = LayoutInflator.inflate(int resId);
if(popup != null) {

    // set up an observer that will be called once the listView's layout is ready
    android.view.ViewTreeObserver viewTreeObserver = listView.getViewTreeObserver();
    if (viewTreeObserver.isAlive()) {

        viewTreeObserver.addOnGlobalLayoutListener(new android.view.ViewTreeObserver.OnGlobalLayoutListener() {

            @Override
            public void onGlobalLayout() {

                // This will be called once the layout is finished, prior to displaying.

                View popup = findViewById(resId);

                if(popup != null) {
                    int width = popup.getMeasuredWidth();
                    int height = popup.getMeasuredHeight();

                    // don't need the listener any more
                    popup.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                }
            }
        });
    }
}
like image 28
Lorne Laliberte Avatar answered Sep 18 '22 13:09

Lorne Laliberte