getmeasuredheight() and getmeasuredwidth() returns 0 after View.measure()
Asked Answered
N

7

24

After measuring a View with a constant dimensions with view.measure(), the getMeasuredHeight() and getMeasureWidth() is returning 0.

layout_view.xml, layout which is inflated to create the view

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="100dp"
    android:layout_height="100dp">
</FrameLayout>

function which measures the dimensions

public void measureView(Context context){
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.layout_view,null,false);

    view.measure( View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);

    Log.d(TAG,"Error width : " + view.getMeasuredWidth());
    Log.d(TAG,"Error height : " + view.getMeasuredHeight());

}
Nystatin answered 26/6, 2014 at 12:22 Comment(3)
see this #14593430Diclinous
@GiruBhai i tried using ViewTreeObserver, its also not workingNystatin
View.MeasureSpec.* can't be used directly, check my answer below.Berth
A
17

When you call view.getMeasuredWidth() in onCreate() or onCreateView(), the view has not been drawn yet. So you need to add a listener and will get a callback when the view is being drawn. Just like this in my code:

final ViewTreeObserver vto = view.getViewTreeObserver();
if (vto.isAlive()) {
    vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            int viewWidth = view.getMeasuredWidth();
            // handle viewWidth here...

            if (Build.VERSION.SDK_INT < 16) {
                vto.removeGlobalOnLayoutListener(this);
            } else {
                vto.removeOnGlobalLayoutListener(this);
            }
        }
    });
}

NOTE: Remove the listener for better performance!

Don't call vto.removeOnGlobalLayoutListener(this) to remove the listener. Call it like this:

vto.getViewTreeObserver()
Adolescence answered 6/3, 2015 at 6:31 Comment(4)
I tried this and it seemed to work in all tested cases but now I see the getMeasuredWidth() returning 0 in production for some users :(Infinity
Thank you! I was using OnPreDrawListener before (but seems it is not compatible with some devices 4.4.4 and 6.0.1). Using onGlobalLayout and removing the listener just when height > 0 it works perfectly.Heteronym
What is v? It came out of nowhere.Shadchan
For some reason getMeasuredWidthonly returns the "right" value after scrolling take place. Is there another way to trigger a correct measurement?Systematics
D
7

Are you measuring the view in onCreate(). The view isn't drawn yet. You have to wait until a time after the view is drawn before you can measure it.

Simple solution for this is to post a runnable to the layout. The runnable will be executed after the layout has happened.

For more info See this post

Edit try to change

view.measure( View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);

to

view.measure( View.MeasureSpec.EXACTLY, View.MeasureSpec.EXACTLY);
Diclinous answered 26/6, 2014 at 12:36 Comment(2)
i am measuring the the view in in onclick method. To avoid the issue you pointed out i am explicitly measuring the view with view.measure()Nystatin
i tried this may also, but still the result is zeroNystatin
L
4

Try this way,hope this will help you to solve your problem.

view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
   @Override
   public void onGlobalLayout() {
     int width = view.getMeasuredWidth();
     int height = view.getMeasuredHeight();

   }
});
Lachlan answered 26/6, 2014 at 12:24 Comment(0)
T
1

if your measured view has visibility set to gone, measuring will return 0. You can set it to visible, measure, and then set back to gone, all from code.

Tripitaka answered 30/10, 2014 at 14:45 Comment(1)
it is set to visible by defaultNystatin
B
0

You can not use View.MeasureSpec.* directly in measure call. Instead first makeMeasureSpec() and then use it to invoke measure():

final int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT/*can be match_parent or some exact value*/, View.MeasureSpec.UNSPECIFIED);
final int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT/*can be match_parent or some exact value*/, View.MeasureSpec.UNSPECIFIED);
view.measure(widthMeasureSpec, heightMeasureSpec);
Berth answered 9/7, 2015 at 12:46 Comment(2)
Thanks, but currently Kotling restricts passing this value (WRAP_CONTENT = -2 < 0). In my case https://mcmap.net/q/328080/-measuring-a-view-before-rendering-it helped in onCreateView(), simply called view.measure(0, 0). In other events you should use getViewTreeObserver(), see #14593430.Wootan
View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT, View.MeasureSpec.UNSPECIFIED);not work, it says Value must be ≥ 0 (was -2)Horologist
C
0

Just in case someone was experiencing this problem with ImageView:

I noticed that if your ImageView doesn't have "android:src" set (i.e. you change it dynamically) it will always return zero from getMeasuredWidth/Height.

A simple workaround would be to set a placeholder for view.

Creaturely answered 24/7, 2017 at 18:10 Comment(1)
getHeight/getMeasuredHeight still gives 0, after setting placeholderAlegar
W
0

You can use getViewTreeObserver in onCreate/onCreateView and other events.

fun setGlobalLayoutListener(view: View, method: () -> Unit) {
    val vto1 = view.viewTreeObserver
    if (vto1.isAlive) {
        vto1.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                val vto2 = view.viewTreeObserver
                if (vto2.isAlive) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                        vto2.removeOnGlobalLayoutListener(this)
                    } else {
                        @Suppress("DEPRECATION")
                        vto2.removeGlobalOnLayoutListener(this)
                    }
                    // Your actions are here:
                    method()
                }
            }
        })
    }
}

And call it: setGlobalLayoutListener(view) {updateUI(view)}.

I also tried

view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)

and then called view.control.measuredWidth in onCreateView()/onViewCreated(). But in some emulators (API 19) it returned wrong results.

Wootan answered 28/5, 2019 at 12:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.