ANDROID - ExpandableListView
Im trying to figure out how to build a view that contains (many of):
- PARENT1 (checkable, expandable)
- CHILD1 (RADIO BUTTON)
- CHILD2 (RADIO BUTTON)
...
- PARENT2 (checkable, expandable)
- CHILD1 (CHECKABLE)
- CHILD2 (CHECKABLE)
...
The point is that parent has to be checkable and based on that children have to change the icon. Can some1 point me into the right direction, because from what i found nothing seems to work for me.
Solution 1:
I assume, you have your data structured somehow, like: ArrayList where
- Parent {name:String, checked:boolean, children:ArrayList} and
- Child {name:String}
If so, you only have to do two things:
- create proper layouts for your parent item renderer and child item renderer
- expand BaseExpandableListAdapter to build up the list yourself.
Here is a small sample about what's in my mind:
layout/grouprow.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:orientation="horizontal"
android:gravity="fill" android:layout_width="fill_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- PARENT -->
<TextView android:id="@+id/parentname" android:paddingLeft="5px"
android:paddingRight="5px" android:paddingTop="3px"
android:paddingBottom="3px" android:textStyle="bold" android:textSize="18px"
android:layout_gravity="fill_horizontal" android:gravity="left"
android:layout_height="wrap_content" android:layout_width="wrap_content" />
<CheckBox android:id="@+id/checkbox" android:focusable="false"
android:layout_alignParentRight="true" android:freezesText="false"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="5px" />
</RelativeLayout>
layout/childrow.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:padding="0px">
<!-- CHILD -->
<TextView android:id="@+id/childname" android:paddingLeft="15px"
android:paddingRight="5px" android:focusable="false" android:textSize="14px"
android:layout_marginLeft="10px" android:layout_marginRight="3px"
android:layout_width="fill_parent" android:layout_height="wrap_content" />
</LinearLayout>
MyELAdapter class: I've declared this as an inner class of MyExpandableList, so i could reach the list of parents directly, without having to pass it as parameter.
private class MyELAdapter extends BaseExpandableListAdapter
{
private LayoutInflater inflater;
public MyELAdapter()
{
inflater = LayoutInflater.from(MyExpandableList.this);
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parentView)
{
final Parent parent = parents.get(groupPosition);
convertView = inflater.inflate(R.layout.grouprow, parentView, false);
((TextView) convertView.findViewById(R.id.parentname)).setText(parent.getName());
CheckBox checkbox = (CheckBox) convertView.findViewById(R.id.checkbox);
checkbox.setChecked(parent.isChecked());
checkbox.setOnCheckedChangeListener(new CheckUpdateListener(parent));
if (parent.isChecked())
convertView.setBackgroundResource(R.color.red);
else
convertView.setBackgroundResource(R.color.blue);
return convertView;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parentView)
{
final Parent parent = parents.get(groupPosition);
final Child child = parent.getChildren().get(childPosition);
convertView = inflater.inflate(R.layout.childrow, parentView, false);
((TextView) convertView.findViewById(R.id.childname)).setText(child.getName());
return convertView;
}
@Override
public Object getChild(int groupPosition, int childPosition)
{
return parents.get(groupPosition).getChildren().get(childPosition);
}
@Override
public long getChildId(int groupPosition, int childPosition)
{
return childPosition;
}
@Override
public int getChildrenCount(int groupPosition)
{
return parents.get(groupPosition).getChildren().size();
}
@Override
public Object getGroup(int groupPosition)
{
return parents.get(groupPosition);
}
@Override
public int getGroupCount()
{
return parents.size();
}
@Override
public long getGroupId(int groupPosition)
{
return groupPosition;
}
@Override
public void notifyDataSetChanged()
{
super.notifyDataSetChanged();
}
@Override
public boolean isEmpty()
{
return ((parents == null) || parents.isEmpty());
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition)
{
return true;
}
@Override
public boolean hasStableIds()
{
return true;
}
@Override
public boolean areAllItemsEnabled()
{
return true;
}
}
You must already have a public class MyExpandableList extends ExpandableListActivity
which has a member:
private ArrayList<Parent> parents;
after you assign a value to this member / load the list of parents, you should also attach your adapter to this view:
this.setListAdapter(new MyELAdapter());
and that's it. You have a checkable-expandable list, and in the CheckUpdateListener
's onCheckedChanged(CompoundButton buttonView, boolean isChecked)
method you can update your parent object's checked state.
Note, that the background color is determined in the getGroupView method, so you don't have to change it anywhere, just call the adapter's notifyDataSetChanged()
method if needed.
Update
you can download the sample source code from this link. It is an eclipse project, but if you are using other developer environment, just simply copy the necessary source files (java + xml).