Determining the size of an Android view at runtime

AndroidAndroid View

Android Problem Overview


I am trying to apply an animation to a view in my Android app after my activity is created. To do this, I need to determine the current size of the view, and then set up an animation to scale from the current size to the new size. This part must be done at runtime, since the view scales to different sizes depending on input from the user. My layout is defined in XML.

This seems like an easy task, and there are lots of SO questions regarding this though none which solved my problem, obviously. So perhaps I am missing something obvious. I get a handle to my view by:

ImageView myView = (ImageView) getWindow().findViewById(R.id.MyViewID);

This works fine, but when calling getWidth(), getHeight(), getMeasuredWidth(), getLayoutParams().width, etc., they all return 0. I have also tried manually calling measure() on the view followed by a call to getMeasuredWidth(), but that has no effect.

I have tried calling these methods and inspecting the object in the debugger in my activity's onCreate() and in onPostCreate(). How can I figure out the exact dimensions of this view at runtime?

Android Solutions


Solution 1 - Android

Use the ViewTreeObserver on the View to wait for the first layout. Only after the first layout will getWidth()/getHeight()/getMeasuredWidth()/getMeasuredHeight() work.

ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
  viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
      view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
      viewWidth = view.getWidth();
      viewHeight = view.getHeight();
    }
  });
}

Solution 2 - Android

There are actually multiple solutions, depending on the scenario:

  1. The safe method, will work just before drawing the view, after the layout phase has finished:

> public static void runJustBeforeBeingDrawn(final View view, final Runnable runnable) { > final OnPreDrawListener preDrawListener = new OnPreDrawListener() { > @Override > public boolean onPreDraw() { > view.getViewTreeObserver().removeOnPreDrawListener(this); > runnable.run(); > return true; > } > }; > view.getViewTreeObserver().addOnPreDrawListener(preDrawListener); > }

Sample usage:

    ViewUtil.runJustBeforeBeingDrawn(yourView, new Runnable() {
        @Override
        public void run() {
            //Here you can safely get the view size (use "getWidth" and "getHeight"), and do whatever you wish with it
        }
    });

2. On some cases, it's enough to measure the size of the view manually:

> view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); > int width=view.getMeasuredWidth(); > int height=view.getMeasuredHeight();

If you know the size of the container:

    val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(maxWidth, View.MeasureSpec.AT_MOST)
    val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(maxHeight, View.MeasureSpec.AT_MOST)
    view.measure(widthMeasureSpec, heightMeasureSpec)
    val width=view.measuredWidth
    val height=view.measuredHeight

3. if you have a custom view that you've extended, you can get its size on the "onMeasure" method, but I think it works well only on some cases :

> protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { > final int newHeight= MeasureSpec.getSize(heightMeasureSpec); > final int newWidth= MeasureSpec.getSize(widthMeasureSpec); > super.onMeasure(widthMeasureSpec, heightMeasureSpec); > }

  1. If you write in Kotlin, you can use the next function, which behind the scenes works exactly like runJustBeforeBeingDrawn that I've written:

     view.doOnPreDraw { actionToBeTriggered() }
    

Note that you need to add this to gradle (found via here) :

android {
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

implementation 'androidx.core:core-ktx:#.#'

Solution 3 - Android

Are you calling getWidth() before the view is actually laid out on the screen?

> A common mistake made by new Android developers is to use the width > and height of a view inside its constructor. When a view’s > constructor is called, Android doesn’t know yet how big the view will > be, so the sizes are set to zero. The real sizes are calculated during > the layout stage, which occurs after construction but before anything > is drawn. You can use the onSizeChanged() method to be notified of > the values when they are known, or you can use the getWidth() and > getHeight() methods later, such as in the onDraw() method.

Solution 4 - Android

Based on @mbaird's advice, I found a workable solution by subclassing the ImageView class and overriding onLayout(). I then created an observer interface which my activity implemented and passed a reference to itself to the class, which allowed it to tell the activity when it was actually finished sizing.

I'm not 100% convinced that this is the best solution (hence my not marking this answer as correct just yet), but it does work and according to the documentation is the first time when one can find the actual size of a view.

Solution 5 - Android

Here is the code for getting the layout via overriding a view if API < 11 (API 11 includes the View.OnLayoutChangedListener feature):

public class CustomListView extends ListView
{
    private OnLayoutChangedListener layoutChangedListener;
    
    public CustomListView(Context context)
    {
        super(context);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b)
    {
        if (layoutChangedListener != null)
        {
            layoutChangedListener.onLayout(changed, l, t, r, b);
        }
        super.onLayout(changed, l, t, r, b);
    }
    
    public void setLayoutChangedListener(
        OnLayoutChangedListener layoutChangedListener)
    {
        this.layoutChangedListener = layoutChangedListener;
    }
}
public interface OnLayoutChangedListener
{
    void onLayout(boolean changed, int l, int t, int r, int b);
}

Solution 6 - Android

You can check this question. You can use the View's post() method.

Solution 7 - Android

This works for me in my onClickListener:

yourView.postDelayed(new Runnable() {				
    @Override
    public void run() {			
        yourView.invalidate();
        System.out.println("Height yourView: " + yourView.getHeight());
        System.out.println("Width yourView: " + yourView.getWidth());				
    }
}, 1);

Solution 8 - Android

Use below code, it is give the size of view.

@Override
public void onWindowFocusChanged(boolean hasFocus) {
       super.onWindowFocusChanged(hasFocus);
       Log.e("WIDTH",""+view.getWidth());
       Log.e("HEIGHT",""+view.getHeight());
}

Solution 9 - Android

I was also lost around getMeasuredWidth() and getMeasuredHeight() getHeight() and getWidth() for a long time.......... later i found that getting the view's width and height in onSizeChanged() is the best way to do this........ you can dynamically get your CURRENT width and CURRENT height of your view by overriding the onSizeChanged() method.

might wanna take a look at this which has an elaborate code snippet. New Blog Post: how to get width and height dimensions of a customView (extends View) in Android http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions.html

Solution 10 - Android

You can get both Position and Dimension of the view on screen

 val viewTreeObserver: ViewTreeObserver = videoView.viewTreeObserver;

if (viewTreeObserver.isAlive) {
    viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            //Remove Listener
            videoView.viewTreeObserver.removeOnGlobalLayoutListener(this);

            //View Dimentions
            viewWidth = videoView.width;
            viewHeight = videoView.height;

            //View Location
            val point = IntArray(2)
            videoView.post {
                videoView.getLocationOnScreen(point) // or getLocationInWindow(point)
                viewPositionX = point[0]
                viewPositionY = point[1]
            }

        }
    });
}

Solution 11 - Android

In Kotlin file, change accordingly

 Handler().postDelayed({

           Your Code

        }, 1)

Solution 12 - Android

If you need to know the dimensions of a View right after it is drawn you can simply call post() on that given View and send there a Runnable that executes whatever you need. It is a better solution than ViewTreeObserver and globalLayout since it gets called repeatedly not just once. This Runnsble will execute only once and you will know the views size.

Solution 13 - Android

works perfekt for me:

 protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);
        CTEditor ctEdit = Element as CTEditor;
        if (ctEdit == null) return;           
        if (e.PropertyName == "Text")
        {
            double xHeight = Element.Height;
            double aHaight = Control.Height;
            double height;                
            Control.Measure(LayoutParams.MatchParent,LayoutParams.WrapContent);
            height = Control.MeasuredHeight;
            height = xHeight / aHaight * height;
            if (Element.HeightRequest != height)
                Element.HeightRequest = height;
        }
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNik ReimanView Question on Stackoverflow
Solution 1 - AndroidVikram BodicherlaView Answer on Stackoverflow
Solution 2 - Androidandroid developerView Answer on Stackoverflow
Solution 3 - AndroidMark BView Answer on Stackoverflow
Solution 4 - AndroidNik ReimanView Answer on Stackoverflow
Solution 5 - AndroidgregmView Answer on Stackoverflow
Solution 6 - AndroidMacarseView Answer on Stackoverflow
Solution 7 - AndroidBiro Csaba NorbertView Answer on Stackoverflow
Solution 8 - AndroidAsif PatelView Answer on Stackoverflow
Solution 9 - AndroidRakibView Answer on Stackoverflow
Solution 10 - AndroidHitesh SahuView Answer on Stackoverflow
Solution 11 - AndroidAkhil GattemaneniView Answer on Stackoverflow
Solution 12 - AndroidSaganView Answer on Stackoverflow
Solution 13 - AndroidATomView Answer on Stackoverflow