Expandable Listview with checkboxes

Costas

Administrator
Staff member
reference - http://www.androidhive.info/2013/07/android-expandable-list-view-tutorial/

Snap111.png


JavaScript:
//@activity
    <LinearLayout
        android:id="@+id/frag_settings_row02_categories_child"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="20dp" >

        <ExpandableListView
            android:id="@+id/frag_settings_row02_categories_explstv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dip" />
    </LinearLayout>
 
JavaScript:
//@the row
<?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="match_parent" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:baselineAligned="false"
        android:layout_marginLeft="35dp"
        android:orientation="horizontal" >
        
        <TextView
            android:id="@+id/frag_settings_row_detail_02_categories_row_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15sp" />
    </LinearLayout>

    <CheckBox
        android:id="@+id/frag_settings_row_detail_02_categories_row_check"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusable="false"
        android:layout_alignParentRight="true"
        android:gravity="right" />

</RelativeLayout>
 
JavaScript:
CREATE TABLE [categories]
(id INTEGER,
category_name TEXT,
parent_id INTEGER);

 
 
JavaScript:
//fragment.java
public class Frag_Settings extends Fragment implements OnItemClickListener {

	// ////////////expandable
	private Frag_Settings_Categories_Adapter listAdapter;
	private ExpandableListView expListView;
	private List<Frag_Settings_Categories> listHeader_Categories;
	private HashMap<Frag_Settings_Categories, List<Frag_Settings_Categories>> listDataChild;
	// ////////////expandable

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		
		expListView = (ExpandableListView) getActivity().findViewById(R.id.frag_settings_row02_categories_explstv);
		listHeader_Categories = new ArrayList<Frag_Settings_Categories>();
		listDataChild = new HashMap<Frag_Settings_Categories, List<Frag_Settings_Categories>>();
		
		listAdapter = new Frag_Settings_Categories_Adapter(getActivity(), listHeader_Categories, listDataChild);
		expListView.setAdapter(listAdapter);

		//fetch recordset by DBASE
		CategoriesDatasource categories_datasource = new CategoriesDatasource(getActivity());

		// get HEAD CATEGORY (categories - parent_id=0)
		for (Categories d : categories_datasource.getAllCategoriess()) {
			if (d.getparent_id()==0)
				listHeader_Categories.add(new Frag_Settings_Categories(d.getid(), d.getcategory_name(), false));
		}

		// get HEAD CHILD ITEMS (sub_categories - parent_id = cat_head)
		List<Frag_Settings_Categories> child_Categories = null;
		for (Frag_Settings_Categories cat_head : listHeader_Categories) {

			// each time instantiate the list
			child_Categories = new ArrayList<Frag_Settings_Categories>();

			// get all sub_categories has parent the cat_head
			for (Categories sub_cat : categories_datasource.getAllCategoriess()) {
				if (sub_cat.getparent_id() == cat_head.getId()) {
					child_Categories.add(new Frag_Settings_Categories(sub_cat.getid(), sub_cat.getcategory_name(), false));
				}
			}

			//for each HEAD CATEGORY - hang children
			listDataChild.put(cat_head, child_Categories);
		}
	}
 
JavaScript:
//Frag_Settings_Categories_Adapter.java
import java.util.HashMap;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;

public class Frag_Settings_Categories_Adapter extends BaseExpandableListAdapter {

	private List<Frag_Settings_Categories> data;
	private HashMap<Frag_Settings_Categories, List<Frag_Settings_Categories>> child;
	private Context context;

	public Frag_Settings_Categories_Adapter(Context context, List<Frag_Settings_Categories> items, HashMap<Frag_Settings_Categories, List<Frag_Settings_Categories>> listChildData) {
		this.context = context;
		this.data = items;
		this.child = listChildData;

	}

	@Override
	public Object getChild(int groupPosition, int childPosititon) {
		return this.child.get(this.data.get(groupPosition)).get(childPosititon);
	}

	@Override
	public long getChildId(int groupPosition, int childPosition) {
		return childPosition;
	}

	// //////////////////// CHILD ITEM
	@Override
	public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
		if (convertView == null) {
			LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			convertView = infalInflater.inflate(R.layout.frag_settings_row_detail_02_categories_row, null);
		}

		ViewHolder holder;
		holder = new ViewHolder();
		holder.rowText = (TextView) convertView.findViewById(R.id.frag_settings_row_detail_02_categories_row_title);
		holder.rowChk = (CheckBox) convertView.findViewById(R.id.frag_settings_row_detail_02_categories_row_check);

		// http://stackoverflow.com/questions/12647001/listview-with-custom-adapter-containing-checkboxes
		holder.rowChk.setTag(String.valueOf(groupPosition) +  "|" + String.valueOf(childPosition)); // store the List<>position in TAG

		holder.rowChk.setOnCheckedChangeListener(new OnCheckedChangeListener() {

			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
				String tag_txt = buttonView.getTag().toString();
				int delimiter_pos =tag_txt.indexOf("|");
				
				int head_id =Integer.parseInt(tag_txt.substring(0,delimiter_pos));
				int child_id = Integer.parseInt(tag_txt.substring(delimiter_pos+1));
				
				child.get(data.get(head_id)).get(child_id).setIs_selected(isChecked); // use of List<>position
			}

		});

		// get CHILD items (search via HEAD item)
		List<Frag_Settings_Categories> single = child.get(data.get(groupPosition));

		// >>>>>>>>>> get - which item the view requires via childPosition
		holder.rowText.setText(single.get(childPosition).getTitle());

		if (single.get(childPosition).getIs_selected())
			holder.rowChk.setChecked(true);
		else
			holder.rowChk.setChecked(false);

		return convertView;
	}

	@Override
	public int getChildrenCount(int groupPosition) {
		return this.child.get(this.data.get(groupPosition)).size();
	}

	@Override
	public Object getGroup(int groupPosition) {
		return this.data.get(groupPosition);
	}

	@Override
	public int getGroupCount() {
		return this.data.size();
	}

	@Override
	public long getGroupId(int groupPosition) {
		return groupPosition;
	}

	// //////////////////// HEAD ITEM
	@Override
	public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {

		if (convertView == null) {
			LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			convertView = infalInflater.inflate(R.layout.frag_settings_row_detail_02_categories_row, null);
		}

		ViewHolder holder;
		holder = new ViewHolder();
		holder.rowText = (TextView) convertView.findViewById(R.id.frag_settings_row_detail_02_categories_row_title);
		holder.rowChk = (CheckBox) convertView.findViewById(R.id.frag_settings_row_detail_02_categories_row_check);

		// http://stackoverflow.com/questions/12647001/listview-with-custom-adapter-containing-checkboxes
		holder.rowChk.setTag(Integer.valueOf(groupPosition)); // store the List<>position in TAG

		holder.rowChk.setOnCheckedChangeListener(new OnCheckedChangeListener() {

			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
				data.get((Integer) buttonView.getTag()).setIs_selected(isChecked); // use of List<>position
				
				notifyDataSetChanged(); //refresh view
			}

		});

		holder.rowText.setText(data.get(groupPosition).getTitle());

		if (data.get(groupPosition).getIs_selected()) {
			holder.rowChk.setChecked(true);
			manipulate_children_value((groupPosition),true);
		} else {
			holder.rowChk.setChecked(false);
			manipulate_children_value(groupPosition,false);
		}

		return convertView;
	}

	private void manipulate_children_value(int head_position, Boolean val) {
//		List<Frag_Settings_Categories> x = child.get(data.get(head_position));
//		
//		for (int i = 0; i < x.size(); i++) {
//			child.get(data.get(head_position)).get(i).setIs_selected(val);
//		}
// similar
				
		for (Frag_Settings_Categories x : child.get(data.get(head_position))) {
			x.setIs_selected(val);
		}
	}
	
    @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
    }

	@Override
	public boolean hasStableIds() {
		//http://stackoverflow.com/a/18217552/1320686
		return true;
	}

	@Override
	public boolean isChildSelectable(int groupPosition, int childPosition) {
		return true;
	}

	class ViewHolder {
		TextView rowText;
		CheckBox rowChk;
	}

}


//Frag_Settings_Categories.java
public class Frag_Settings_Categories {
	private int id;
	private String title;
	private Boolean is_selected;
	
	public Frag_Settings_Categories(long id,String title, Boolean is_selected){
		this.id=(int) id;
		this.title=title;
		this.is_selected=is_selected;
	}
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public Boolean getIs_selected() {
		return is_selected;
	}
	public void setIs_selected(Boolean is_selected) {
		this.is_selected = is_selected;
	}
}
 
Top