0

I have created a GridView control, which inhertis from a ScrollView, the idea of this control, is that it will contain multiple Views arranged in a grid format with a given number of columns and rows.

When the view is first built, the GridView doesn't know the size of its container, so I wait until the onSizeChanged method is called, then I apply the relevant sizing.

When the below is run, it doesn't re-size the grid to show it correctly, each control is only as big as it needs to be to show the text.

When the `onSizeChanged' method is called, it has the correct size, and applies the correct size to each child view, but it doesn't affect the way the controls are drawn (i.e. they're still all bunched up on the top left of the screen).

Despite this, I have actually got it working, but it draws twice. I do this by creating a Runnable which calls ResizeList. Then calling new Handler().post(r) straight after I call BuildIt.

Although this is a solution, I just don't understand why it doesn't work in the below form.

Incidentally, if the GridView is the main View added to the Activity, it displays fine, it's only when it's subsequently added. Which is why I have the Button, which you have to press to show the grid.

Can anyone suggest why the below code doesn't work properly?

public class MainActivity extends Activity  {
    GridView sv;
    FrameLayout flay;
    @Override protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        flay=new FrameLayout(this);
        this.setContentView(flay);
        Button b=new Button(this);
        b.setText("press me to show grid view");
        b.setOnClickListener(ocl);
        flay.addView(b);
    }

    OnClickListener ocl=new OnClickListener() 
    {
        @Override public void onClick(View v)
        {
            BuildIt();
        }};

    private void BuildIt()
    {
        flay.removeAllViews(); // remove the button control
        sv=new GridView(this);

        for (int c1=0 ; c1<30 ; c1++)
        {
            TextView tv=new TextView(this);
            tv.setText("Item "+c1);
            tv.setGravity(android.view.Gravity.CENTER);
            sv.addListItem(tv);
        }
        flay.addView(sv);
        sv.ConstructList();
    }
}

The GridView class

public class GridView extends ScrollView
{
    final int rows=4;
    final int cols=4;
    private ArrayList<View> allViews=new ArrayList<View>();
    private LinearLayout ll;
    public GridView(Context context)
    {
        super(context);
        ll=new LinearLayout(context);
        ll.setOrientation(LinearLayout.VERTICAL);
        this.addView(ll);
    }

    public void addListItem(View v)
    {
        allViews.add(v);
    }

    public void ConstructList()
    {
        int c1=0;
        ll.removeAllViews(); // Just in case we're re-building
        LinearLayout row=null;
        for (View v : allViews)
        {
            if (c1%cols==0)
            {
                row=new LinearLayout(this.getContext());
                ll.addView(row);
            }
            row.addView(v);
            c1++;
        }
    }

    private void ResizeList()
    {
        int useHeight=getHeight()/rows;
        int useWidth=getWidth()/cols;
        LinearLayout.LayoutParams lpCol=new LinearLayout.LayoutParams(useWidth, useHeight);
        Log.i("log","About to set width/height="+useWidth+"/"+useHeight);
        int numKids= ll.getChildCount();
        for (int c1=0 ; c1<numKids ; c1++)
        {
            LinearLayout ll2=(LinearLayout)ll.getChildAt(c1);
            for (int c2=0 ; c2<ll2.getChildCount() ; c2++) // use getChildCount rather than cols, just in case it's the last one
            {
                View v=ll2.getChildAt(c2);
                v.setLayoutParams(lpCol);
            }
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        super.onSizeChanged(w, h, oldw, oldh);
        ResizeList();
    }
}
Rich S
  • 3,248
  • 3
  • 28
  • 49

2 Answers2

0

I have a function which is used to resize the child's width and height in gridView.

May be this could help you :

public static void setGridChild_Height(GridView gridView, int columns) {
        ListAdapter listAdapter = gridView.getAdapter();
        if (listAdapter == null) {
            // pre-condition
            return;
        }

        int totalHeight = 0;
        int items = listAdapter.getCount();
        int rows = 0;

        for (int j = 0; j < items; j++) {
            View view = gridView.getChildAt(j);
            if (view != null && view.getHeight() > totalHeight) {
                totalHeight = view.getHeight();
            }
        }
        System.out.println("totalHeight -> " + totalHeight);
        if (totalHeight > 0) {
            for (int j = 0; j < items; j++) {
                View view = gridView.getChildAt(j);
                if (view != null && view.getHeight() < totalHeight) {
                    view.setMinimumHeight(totalHeight);
                }
            }
        }

        // View listItem = listAdapter.getView(0, null, gridView);
        // listItem.measure(0, 0);
        // totalHeight = listItem.getMeasuredHeight();
        //
        // float x = 1;
        // if (items > columns) {
        // x = items / columns;
        // rows = (int) (x + 1);
        // totalHeight *= rows;
        // }
        //
        // ViewGroup.LayoutParams params = gridView.getLayoutParams();
        // params.height = totalHeight;
        // gridView.setLayoutParams(params);
    }

Try to change logic as per your requirement. Code is not tested perfectly.

Kirankumar Zinzuvadia
  • 1,249
  • 10
  • 17
0

It's because onSizeChanged when newly added to the view hierarchy uses it's old sizes of "0" (according to the docs: http://developer.android.com/reference/android/view/View.html#onSizeChanged(int, int, int, int))

I think what you want is to a addOnLayoutChangedListener : http://developer.android.com/reference/android/view/View.html#addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener)

Using the ViewTreeObserver might be another option that will work for you: How can you tell when a layout has been drawn?

Community
  • 1
  • 1
Jim
  • 10,172
  • 1
  • 27
  • 36
  • Thanks for your suggestion, but when `onSizeChanged` is called, it has the correct width/height values, and I use them to set the `LayoutParameters`. It still doesn't take it into account. I will try the `addOnLayoutChangedListener` – Rich S Sep 03 '15 at 14:36
  • I was just quoting the docs, and you said it worked in the "main view" but not when added, which is what the docs say to expect - and seemed to also be the issue for me. Odd that you would see a different result, but hope the rest of it helps. – Jim Sep 03 '15 at 14:42