29

In a Fragment, I am inflating a Layout with multiple child View. I need to get the dimensions (width and height) of one of them which is a custom view.

Inside the custom view class I can do it easily. But if I try to do it from the fragment I always get 0 as dimensions.

 public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); View culoide = view.findViewWithTag(DRAW_AREA_TAG); Log.d("event", "culoide is: "+culoide.getWidth()); // always 0 } 

I figure that onViewCreated should be the right place to get it, but well this happens. I tried before super.onViewCreated, in debug it looks like 'findViewWithTag' finds the right view, tried with api 7 v4 support only.

Any help?

7 Answers 7

46

You must wait until after the first measure and layout in order to get nonzero values for getWidth() and getHeight(). You can do this with a ViewTreeObserver.OnGlobalLayouListener

public void onViewCreated(final View view, Bundle saved) { super.onViewCreated(view, saved); view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { public void onGlobalLayout() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { view.getViewTreeObserver().removeOnGlobalLayoutListener(this); } else { view.getViewTreeObserver().removeGlobalOnLayoutListener(this); } // get width and height of the view } }); } 
Sign up to request clarification or add additional context in comments.

6 Comments

+1 thanks :) ; removeGlobalOnLayoutListener is today already deprecated ; but that's already a different issue
The deprecated method calls through to the new one (and in fact I don't know if it was worth deprecating just because of the name), but I've edited my code anyway.
Or just override onSizeChanged().
In my case I want to use the getWidth() to adjust some padding/margin. I cannot override onSizeChanged() since it is called during layout and changes to padding/margin would not be persisted. The OnGlobalLayoutListener fires when layout is finished, no problems there.
Remember to set mView=null in onDestroyView().
|
6

My preferred method is to add an OnLayoutChangeListener to the view that you want to track itself

CustomView customView = ... customView.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 remove the listener in the callback if you only want the initial layout.

Comments

3

Using ViewTreeObserver.OnGlobalLayoutListener, View.post(Runnable action) or onWindowFocusChanged() isn't the best solution. This article (note: I am the author of this article) explains why and provides a working solution using doOnLayout kotlin extension, which is based on View.OnLayoutChangeListener. If you want it in Java, in the article there's a link to doOnLayout source code, it's very simple and you can do something similar in Java too.

Comments

2

You have to wait until the onSizeChanged() method is called before you can reliably determine the View size.

This is called during layout when the size of this view has changed. If you were just added to the view hierarchy, you're called with the old values of 0.

Comments

1

Try calling

culoide.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);

first, then try getWidth() and getHeight()

Comments

0

Try checking in onWindowFocusChanged and it should have valid values:

public void onWindowFocusChanged (boolean hasFocus) { } 

I had a similar issue where I needed to get width and height of a widget and this was the function in which I could guarantee the widget reported it's correct size.

Comments

0

this is a real pain especially because you expected with a name like onViewCreated in fragments lifecycle that the view is ready. for me get the fragment view itself like this:

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) getView()?.let{ it.doOnLayout{// do your UI work here } } } 

this ensures the fragments getView has actually had one layout pass already.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.