12

I have created a custom layout which extends ViewGroup. Everything is working fine and I am getting the layout as expected.

I want to dynamically change an element in the layout. However this is not working as I am calling it in onCreate and till that time the entire layout is not actually (drawn) inflated onto the screen and hence do not have actual size.

Is there any event which can be used to find out when the inflation of the layout is done? I tried onFinishInflate but that would not work as Viewgroup has multiple views and this would be called multiple times.

I am thinking of creating an interface in the Custom layout class but not sure when to fire it?

PravinCG
  • 7,688
  • 3
  • 30
  • 55

2 Answers2

30

If I understand your requirements correctly, an OnGlobalLayoutListener may give you what you need.

  View myView=findViewById(R.id.myView);
  myView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //At this point the layout is complete and the 
                //dimensions of myView and any child views are known.
            }
        });
Phillip Fitzsimmons
  • 2,915
  • 2
  • 21
  • 20
  • I have been using this for sometime to adjust textsize in textview, never knew this can be used for ViewGroup as well. Thanks for the help! – PravinCG Sep 22 '11 at 16:22
2

Usually when creating a custom layout extending View or ViewGroup, you have to override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) and protected void onLayout(boolean changed, int left, int top, int right, int bottom). These are called during the process of inflation in order to obtain the size and location information related to the view. Also, subsequently, if you are extending ViewGroup you are to call measure(int widthMeasureSpec, int heightMeasureSpec) and layout(int l, int t, int r, int b) on every child view contained within. (measure() is called in onMeasure() and layout() is called in onLayout()).

Anyway, in onMeasure(), you generally do something like this.

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
   // Gather this view's specs that were passed to it
   int widthMode = MeasureSpec.getMode(widthMeasureSpec);
   int widthSize = MeasureSpec.getSize(widthMeasureSpec);
   int heightMode = MeasureSpec.getMode(heightMeasureSpec);
   int heightSize = MeasureSpec.getSize(heightMeasureSpec);

   int chosenWidth = DEFAULT_WIDTH;
   int chosenHeight = DEFAULT_HEIGHT;
   if(widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.EXACTLY)
      chosenWidth = widthSize;
   if(heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.EXACTLY)
      chosenHeight = heightSize;

   setMeasuredDimension(chosenWidth, chosenHeight);

   *** NOW YOU KNOW THE DIMENSIONS OF THE LAYOUT ***
}

In onLayout() you get the actual pixel coordinates of the View, so you can get the physical size like so:

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
   // Android coordinate system starts from the top-left
   int width = right - left;
   int height = bottom - top;
}
DeeV
  • 35,865
  • 9
  • 108
  • 95
  • Thanks for the response. I have done all what you have prescribed my query is since the value is going to be dynamic, how do I pass that data from the Activity and more importantly when (event) ?? – PravinCG Sep 22 '11 at 16:03
  • 1
    Ok. I thought you were changing the view dynamically within the view. If that were the case, you can use those two methods to find out your coordinates (even before it's in view). Another option may be using `onWindowFocusChanged()` which is part of `Activity`. According to the documentation `Called when the current Window of the activity gains or loses focus. This is the best indicator of whether this activity is visible to the user. The default implementation clears the key tracking state, so should always be called. ` I've used it to determine when a window was in view (thus inflated). – DeeV Sep 22 '11 at 16:08
  • +1, Thanks for the response. The above method is not the reliable way of doing it though might work in some cases. – PravinCG Sep 22 '11 at 16:19