Search code examples
androidandroid-widget

List View check box not checked in non visible rows


I am creating a list view with each row having custom layout. Each custom layout has a check-box. I have a check box, which on click has to click all the check boxes in the list view. I am able to click check boxes in visible rows but I am facing problem with non visible rows. I tried checking all in list adapter but its not working.

MainActivity.java

public class MainActivity extends Activity implements OnItemClickListener{

    ListView listView;
    ArrayAdapter<Model> adapter;
    static List<Model> list = new ArrayList<Model>();
    public static int count = 0;

    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);

        listView = (ListView) findViewById(R.id.my_list);
        adapter = new MyAdapter(this,getModel());
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(this);
        count = listView.getCount();
    }

    @Override
    public void onItemClick(AdapterView<?> arg0, View v, int position, long arg3) {
        TextView label = (TextView) v.getTag(R.id.label);
        CheckBox checkbox = (CheckBox) v.getTag(R.id.check);
        Toast.makeText(v.getContext(), label.getText().toString()+" "+isCheckedOrNot(checkbox), Toast.LENGTH_LONG).show();
    }

    private String isCheckedOrNot(CheckBox checkbox) {
        if(checkbox.isChecked())
            return "is checked";
        else
            return "is not checked";
    }

    private List<Model> getModel() {
        list.add(new Model("Linux"));
        list.add(new Model("Windows7"));
        list.add(new Model("Suse"));
        list.add(new Model("Eclipse"));
        list.add(new Model("Ubuntu"));
        list.add(new Model("Solaris"));
        list.add(new Model("Android"));
        list.add(new Model("iPhone"));
        list.add(new Model("Java"));
        list.add(new Model(".Net"));
        list.add(new Model("PHP"));
        list.add(new Model("U1"));
        list.add(new Model("S1"));
        list.add(new Model("A1"));
        list.add(new Model("i1"));
        list.add(new Model("J1"));
        list.add(new Model(".N1"));
        list.add(new Model("PP1"));
        return list;
    }
}

MyAdapter .java

public class MyAdapter extends ArrayAdapter<Model> {

    private final List<Model> list;
    private final Activity context; 

    TextView text;
    CheckBox checkbox;
    boolean flag;

    public MyAdapter(Activity context, List<Model> list) {
        super(context, R.layout.row, list);
        this.context = context;
        this.list = list;
    }

    static class ViewHolder {
        protected TextView text;
        protected CheckBox checkbox;
    }

    @Override
    public View getView(final int position, View convertView, final ViewGroup parent) {

        final CheckBox c = (CheckBox) ((ViewGroup) parent.getParent()).getChildAt(0);


        if (convertView == null) {
            LayoutInflater inflator = context.getLayoutInflater();
            convertView = inflator.inflate(R.layout.row, null);
        }

            text = (TextView) convertView.findViewById(R.id.label);
            checkbox = (CheckBox) convertView.findViewById(R.id.check);
            checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

                        @Override
                        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                            int getPosition = (Integer) buttonView.getTag(); 
                            list.get(getPosition).setSelected(buttonView.isChecked());
                        }
                    });

        checkbox.setTag(position); 

        text.setText(list.get(position).getName());

        c.setOnCheckedChangeListener(new OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                for (int i = 0; i < parent.getChildCount(); i++) {

                    RelativeLayout r = (RelativeLayout) parent.getChildAt(i);

                    CheckBox check1 = (CheckBox) r.getChildAt(1);

                    if(check1 instanceof CheckBox){

                        check1.setChecked(true);
                    }
                }
            }
        });

        if(flag){

            list.get(position).setSelected(flag);

        }

        checkbox.setChecked(list.get(position).isSelected());   

        return convertView;
    }
}

main.xml

 <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
        <CheckBox
            android:id="@+id/check"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_marginLeft="4dip"
            android:layout_marginRight="10dip"
            android:focusable="false"
            android:focusableInTouchMode="false" >
        </CheckBox>

        <ListView
            android:id="@+id/my_list"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />

    </LinearLayout>

row.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <TextView
        android:id="@+id/label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@+id/label"
        android:textSize="30sp" >
    </TextView>

    <CheckBox
        android:id="@+id/check"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_marginLeft="4dip"
        android:layout_marginRight="10dip"
        android:focusable="false"
        android:focusableInTouchMode="false" >
    </CheckBox>

</RelativeLayout>

Solution

  • A list view only has as many children as you can see, therefore getChildCount() will only return what is visible.

    You will need to have a field in your Model class that stores its checked state. So in your adapter's getView method you'll do something like

    Model myModel = getItem(position);
    checkBox.setChecked(myModel.isChecked());
    

    Select all should loop through the list and mark all Model objects as checked and update the visible views in the list view. Next time you scroll the checkbox will read its checked state from the relevant model object, from inside getView()