In our last post we saw how to create simple custom listview, It does not have any state to save when scrolled. But implementing ListView with check boxes & saving the selected items are little tricky. since listview elements are destroyed & recreated.

ListView with CheckBox
ListView Model


To handle selected items, we need a variable to save the selected state of each items. Hence we will be using SparseBooleanArrays (I have no clue how I came across this)

 This post is a continuation of prev post, so please refer prev post incase if you have any queries.

Create a ListView in the View of our current layout. "activity_main.xml" (refer last post)


Create a customView  "custom_list_view.xml"


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:background="#EEE"
 android:minHeight="90dp"
 android:padding="4dp"
 tools:ignore="HardcodedText,ContentDescription" >

    <TextView
 android:id="@+id/textView"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_centerVertical="true"
 android:layout_marginLeft="31dp"
 android:layout_toRightOf="@+id/imageView"
 android:text="Content"
 android:textSize="21sp" />

    <ImageView
 android:id="@+id/imageView"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignParentLeft="true"
 android:layout_centerVertical="true"
 android:layout_marginLeft="15dp"
 android:maxHeight="60dp"
 android:maxWidth="60dp"
 android:scaleType="fitXY"
 android:src="@drawable/ic_launcher" />

    <CheckBox
 android:id="@+id/checkBox"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignParentRight="true"
 android:layout_centerVertical="true"
 android:focusable="false"
 android:focusableInTouchMode="false"
 android:padding="16dp" />

</RelativeLayout>


we get this with the above code.

ListView with CheckBox

Inflate this layout as adapter to ListView (refer last post)

 

 

Inflating header to custom listView.

 

     This time let's add header to listview (this will scroll with list view, this will be useful when header is different from that of contents.)
Inflate header similar to that of custom listview. Add header before setting adaper to listview.


Create a customView  "custom_list_view_header.xml"


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:background="#EEE"
 android:minHeight="90dp"
 android:padding="4dp"
 tools:ignore="HardcodedText,ContentDescription" >

    <TextView
 android:id="@+id/textView1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_centerHorizontal="true"
 android:layout_centerVertical="true"
 android:layout_marginLeft="31dp"
 android:text="Content"
 android:textSize="21sp" />

    <CheckBox
 android:id="@+id/checkBox_header"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignParentRight="true"
 android:layout_centerVertical="true"
 android:focusable="false"
 android:focusableInTouchMode="false"
 android:padding="16dp" />

</RelativeLayout>

ListView Header



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

mListView = (ListView) findViewById(R.id.list_view);
CustomAdapter adapter = new CustomAdapter(this);
final View headerView = getLayoutInflater().inflate(R.layout.custom_list_view_header, mListView, false);
checkBox_header = (CheckBox) headerView.findViewById(R.id.checkBox_header);
mListView.setAdapter(adapter);

    }


when activity is recreated, header is added again to avoid this, header is added inside custom if else.

if (isNotAdded)
 {
    final View headerView = getLayoutInflater().inflate(R.layout.custom_list_view_header, mListView, false);
    checkBox_header = (CheckBox) headerView.findViewById(R.id.checkBox_header);
    isNotAdded = false;
 }

 

 

Create a sub class CustomAdapter extending BaseAdapter, add unimplemented methods


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

    View mView = convertView;

    if (mView == null) {

/*
 * LayoutInflater
 */
final LayoutInflater sInflater = (LayoutInflater) sActivity.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);

/*
 * Inflate Custom List View
 */
mView = sInflater.inflate(R.layout.custom_list_view, null, false);

    }

    /* **************CUSTOM LISTVIEW OBJECTS**************** */

    /*
     * DO NOT MISS TO ADD "mView"
     */
    final TextView sTV1 = (TextView) mView.findViewById(R.id.textView);
    final ImageView sIMG = (ImageView) mView.findViewById(R.id.imageView);
    final CheckBox mCheckBox = (CheckBox) mView.findViewById(R.id.checkBox);

    /* **************CUSTOM LISTVIEW OBJECTS**************** */

    /* **************ADDING CONTENTS**************** */
    sTV1.setText(MainActivityjacobe.textviewContent[position]);
    sIMG.setImageResource(R.drawable.logo);

    /* **************ADDING CONTENTS**************** */

    /*
     * Return View here
     */
    return mView;
}


Add "OnCheckedChangeListener" to check box.


Set each checkbox, to checked/unchecked from SparseBooleanArray
  SparseBooleanArray mChecked = new SparseBooleanArray();

    mCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    if (isChecked) {

/*
 * Saving Checked Position
 */
mChecked.put(position, isChecked);

    } else {
/*
 * Removed UnChecked Position
 */
mChecked.delete(position);

    }

}
    });

    /*
     * Set CheckBox "TRUE" or "FALSE" if mChecked == true
     */
    mCheckBox.setChecked((mChecked.get(position) == true ? true : false));



To select all the CheckBoxes in listview, when header CheckBox is selected & vice-versa


Set "setOnClickListener" NOT "setOnCheckedChangeListener" for CheckBox in header "checkBox_header"


  
    /*
     * Select All / None DO NOT USE "setOnCheckedChangeListener" here.
     */
    checkBox_header.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

    /*
     * Set all the checkbox to True/False
     * here reference for `i` is count, do not use `mChecked.size()`
     */
    for (int i = 0; i < count; i++)
    {
mChecked.put(i, checkBox_header.isChecked());
    }
    /*
     * Update View
     */
    adapter.notifyDataSetChanged();

}
    });


Set "OnItemClickListener" after adding Adapter


Since header is added position = position - 1 only when position > 0

/*
 * Set "OnItemClickListener" after adding Adapter
 */
mListView.setOnItemClickListener(new OnItemClickListener() {

    @Override
    public void onItemClick(AdapterView parent, View view, int position, long id) {

/*
 * Use "if else" only if header is added
 */
if (position == 0)
{
    Toast.makeText(getApplicationContext(),
    checkBox_header.getId() + "\n" + checkBox_header.isChecked(),
    Toast.LENGTH_SHORT).show();
} else {
    position = position - 1; // "-1" If Header is Added
    Toast.makeText(getApplicationContext(),
    textviewContent[position] + "\n" + mChecked.get(position),
    Toast.LENGTH_SHORT).show();
}

    }
});



To uncheck header CheckBox when CheckBoxes in ListView are unchecked & check the header CheckBox when all CheckBoxes in ListView are checked manually



    mCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    if (isChecked) {

/*
 * Saving Checked Position
 */
mChecked.put(position, isChecked);

/*
 * Find if all the check boxes are true
 */
if (isAllValuesChecked())
{
    /*
     * set HeaderCheck box to true
     */
    checkBox_header.setChecked(isChecked);
}

    } else {
/*
 * Removed UnChecked Position
 */
mChecked.delete(position);

/*
 * Remove Checked in Header
 */
checkBox_header.setChecked(isChecked);

    }

}
    });

/*
 * Find if all values are checked.
 */
protected boolean isAllValuesChecked() {

    for (int i = 0; i < count; i++) {
if (!mChecked.get(i))
{
    return false;
}
    }

    return true;
}




Putting all the functions together



/**
 * Author  : VenomVendor
 * Dated  : 6 Dec, 2013 1:19:40 AM, IST.
 * Project  : SimpleListView-CheckBox
 * Contact  : info@VenomVendor.com
 * URL   : https://www.google.co.in/search?q=VenomVendor
 * Copyright(c)  : WTF.!
 **/

package vee.simplelistview.checkbox;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

    private ListView mListView;
    private static int count = 0;
    private static boolean isNotAdded = true;
    private CheckBox checkBox_header;
    final CustomAdapter adapter = new CustomAdapter(this);
    final static String[] textviewContent = {
            "Content1", "Content2", "Content3", "Content4", "Content5", "Content6",
            "Content7", "Content8", "Content9", "Content10", "Content11",
            "Content12", "Content13", "Content14", "Content15", "Content16",
    };

    /**
     * To save checked items, and re-add while scrolling.
     */
    SparseBooleanArray mChecked = new SparseBooleanArray();

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

        mListView = (ListView) findViewById(R.id.list_view);

        /*
         * To avoid adding multiple times
         */
        if (isNotAdded) {

            /*
             * mListView >> (ListView) //DO NOT ADD `NULL` here.
             */

            final View headerView = getLayoutInflater().inflate(R.layout.custom_list_view_header,
                    mListView, false);

            checkBox_header = (CheckBox) headerView.findViewById(
                    R.id.checkBox_header);

            /*
             * Select All / None DO NOT USE "setOnCheckedChangeListener" here.
             */
            checkBox_header.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {

                    /*
                     * Set all the checkbox to True/False
                     */
                    for (int i = 0; i < count; i++) {
                        mChecked.put(i, checkBox_header.isChecked());
                    }

                    /*
                     * Update View
                     */
                    adapter.notifyDataSetChanged();

                }
            });

            /*
             * Add Header to ListView
             */
            mListView.addHeaderView(headerView);

            isNotAdded = false;
        }

        /*
         * Set Adapter After Adding Header
         */
        mListView.setAdapter(adapter);

        /*
         * Set "OnItemClickListener" after adding Adapter
         */
        mListView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id) {

                /*
                 * Use "if else" only if header is added
                 */
                if (position == 0) {
                    Toast.makeText(getApplicationContext(),
                            checkBox_header.getId() + "\n" + checkBox_header.isChecked(),
                            Toast.LENGTH_SHORT).show();
                } else {
                    position = position - 1; // "-1" If Header is Added
                    Toast.makeText(getApplicationContext(),
                            textviewContent[position] + "\n" + mChecked.get(position),
                            Toast.LENGTH_SHORT).show();
                }

            }
        });

    }

    /*
     * CustomAdapter
     */
    public class CustomAdapter extends BaseAdapter {

        Activity sActivity;

        public CustomAdapter(final Activity mActivity) {
            this.sActivity = mActivity;
        }

        @Override
        public int getCount() {

            /*
             * Length of our listView
             */
            count = MainActivity.textviewContent.length;
            return count;
        }

        @Override
        public Object getItem(int position) {

            /*
             * Current Item
             */
            return position;
        }

        @Override
        public long getItemId(int position) {

            /*
             * Current Item's ID
             */
            return position;
        }

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

            View mView = convertView;

            if (mView == null) {

                /*
                 * LayoutInflater
                 */
                final LayoutInflater sInflater = (LayoutInflater) sActivity.getSystemService(
                        Context.LAYOUT_INFLATER_SERVICE);

                /*
                 * Inflate Custom List View
                 */
                mView = sInflater.inflate(R.layout.custom_list_view, null, false);

            }

            /* **************CUSTOM LISTVIEW OBJECTS**************** */

            /*
             * DO NOT MISS TO ADD "mView"
             */
            final TextView sTV1 = (TextView) mView.findViewById(R.id.textView);
            final ImageView sIMG = (ImageView) mView.findViewById(R.id.imageView);
            final CheckBox mCheckBox = (CheckBox) mView.findViewById(
                    R.id.checkBox);

            /* **************CUSTOM LISTVIEW OBJECTS**************** */

            /* **************ADDING CONTENTS**************** */
            sTV1.setText(MainActivity.textviewContent[position]);
            sIMG.setImageResource(R.drawable.logo);

            mCheckBox.setOnCheckedChangeListener(
                    new OnCheckedChangeListener() {

                        @Override
                        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                            if (isChecked) {

                                /*
                                 * Saving Checked Position
                                 */
                                mChecked.put(position, isChecked);

                                /*
                                 * Find if all the check boxes are true
                                 */
                                if (isAllValuesChecked()) {

                                    /*
                                     * set HeaderCheck box to true
                                     */
                                    checkBox_header.setChecked(isChecked);
                                }

                            } else {

                                /*
                                 * Removed UnChecked Position
                                 */
                                mChecked.delete(position);

                                /*
                                 * Remove Checked in Header
                                 */
                                checkBox_header.setChecked(isChecked);

                            }

                        }
                    });

            /*
             * Set CheckBox "TRUE" or "FALSE" if mChecked == true
             */
            mCheckBox.setChecked((mChecked.get(position) == true ? true : false));

            /* **************ADDING CONTENTS**************** */

            /*
             * Return View here
             */
            return mView;
        }

        /*
         * Find if all values are checked.
         */
        protected boolean isAllValuesChecked() {

            for (int i = 0; i < count; i++) {
                if (!mChecked.get(i)) {
                    return false;
                }
            }

            return true;
        }

    }
}

 

CustomListView with CheckBox on GitHub


Final Required View