SathMK
SathMK

Reputation: 1171

getmeasuredheight() and getmeasuredwidth() returns 0 after View.measure()

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());

}

Upvotes: 24

Views: 35735

Answers (7)

CoolMind
CoolMind

Reputation: 28783

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.

Upvotes: 0

M-Wajeeh
M-Wajeeh

Reputation: 17284

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

Upvotes: 0

Francis Shi
Francis Shi

Reputation: 395

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

Upvotes: 17

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.

Upvotes: 0

Radu Simionescu
Radu Simionescu

Reputation: 4676

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.

Upvotes: 1

Giru Bhai
Giru Bhai

Reputation: 14398

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

Upvotes: 7

Hareshkumar Chhelana
Hareshkumar Chhelana

Reputation: 24848

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();

   }
});

Upvotes: 4

Related Questions