Question

I deleted almost all code in my project to find a hiding bug. There was a GridView that containing a frame layout, and the layout contained CheckBox. But I couldn't check the first check box.(others worked)

Finally (I think) I found an answer. But this is so weird. When I deleted lines for recycling convertView, the bug was gone. I changed from :

        if(convertView == null) {
            layout = (FrameLayout)View.inflate(maincon, R.layout.taste_brand, null);
        } else {
            layout = (FrameLayout) convertView;
        }

to FrameLayout layout = (FrameLayout)View.inflate(maincon, R.layout.taste_brand, null);.

I really have no idea of this stuation. I attach rest codes.

TasteGridAdapter.java:

public class TasteGridAdapter extends BaseAdapter {

    Context maincon;

    public TasteGridAdapter(Context context) {
        maincon = context;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        FrameLayout layout;

        if(convertView == null) {
            layout = (FrameLayout)View.inflate(maincon, R.layout.taste_brand, null);
        } else {
            layout = (FrameLayout) convertView;
        }

        layout.setLayoutParams(new GridView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));

        return layout;
    }

    @Override
    public int getCount() {
        return 3;
    }

    @Override
    public Object getItem(int position) {
        return position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

}

onCreate of the activity :

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.taste);

    TasteGridAdapter adapter = new TasteGridAdapter(this);
    GridView grid = (GridView) findViewById(R.id.taste_grid);
    grid.setAdapter(adapter);
}

taste.xml:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <GridView
        android:layout_weight="1"
        android:id="@+id/taste_grid"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:columnWidth="87dip"
        android:gravity="center"
        android:horizontalSpacing="4dip"
        android:numColumns="auto_fit"
        android:padding="2dip"
        android:stretchMode="columnWidth"
        android:verticalSpacing="4dip" />
</LinearLayout>

taste_brand.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="87dp"
    android:layout_height="58dp">
    <CheckBox
        android:id="@+id/taste_brand_check"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</FrameLayout>
Was it helpful?

Solution

I encountered similar problem with first item in GridView. To resolve issue, remove 'new' keyword, and change existing views LayoutParams like that:

LayoutParams lp = layout.getLayoutParams();
lp.height = someHeight;

...do something with these LayoutParams. This hack resolves my issues. Conclusion, try to avoid creation of new LayoutParams object through "new".

OTHER TIPS

layout.setLayoutParams(new GridView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));

put this line in this condition,

if(convertView == null) {

}

I was faced same problem, but i try this and its work for me. I hope it also work for you.

What you're experiencing has to do with the way Android recycles views in ListView, GridView, etc. You mention that your first checkbox is uncheckable, while your others remain working. I think you'll notice that the others only appear to work properly, since you haven't handled the recycling properly.

The reason your line

FrameLayout layout = (FrameLayout)View.inflate(maincon, R.layout.taste_brand, null);

seems to fix the problem is because this now inflates the views again each time they are used. I'll admit, when I started with this, re-inflating the views seemed to be the best solution; it entirely defeats the purpose of recycling, however, and you lose all the performance benefits otherwise gained.

So now to fix your problem:

First, I highly recommend using the ViewHolder pattern in conjunction with your BaseAdapter. More information on that can be found here.

Second, you should probably create a boolean array to match all the items in your GridView, and use it to determine whether or not an item should be clicked. Set the value of the corresponding boolean inside your checkbox listener and use that value inside getView(..) to check or uncheck that particular box.

An overall better solution might be to use an array (or list) of models inside your adapter class, each of these containing a boolean field accessible through isChecked and setChecked(boolean). Again, you would use this inside your getView(..) to display the views properly and change the value inside your checkbox OnCheckedChangeListener.

Hope that helps.

As jonstaff says, it's to do with View recycling.

If you're using a custom Adapter class for your GridView View binding, try modifying its getView() method to always instantiate a new View like:

public View getView(int position, View convertView, ViewGroup parent){
    SomeView v = new SomeView(context); // <--- here
    ...
    return v;
}

Instead of the typical:

public View getView(int position, View convertView, ViewGroup parent){
    SomeView v;
    if (convertView == null)
        v = new SomeView (context);
    else
        v= (SomeView)convertView;
    ...
    return v;
}

This may affect performance, but it solved my problem for a small GridView of Buttons.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top