Working demo on Github.
First of all, we will need a custom ExpandableListView, which will adjust its size using MeasureSpec. By using the AT_MOST mode, we set the size dynamically, but with a maximum pixel size.
class CustomExpandableListView extends ExpandableListView {
public CustomExpandableListView(Context context) {
super(context);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/*
* Adjust height
*/
heightMeasureSpec = MeasureSpec.makeMeasureSpec(500, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
The next step is to create two Adapters.
The first one, which will extend the BaseExpandableListAdapter will be responsible for showing the first level.
public class Adapter extends BaseExpandableListAdapter {
private List<object> objects;
private Activity activity;
private LayoutInflater inflater;
public Adapter(Activity activity, List<object> objects) {
this.objects= objects;
this.activity= activity;
this.inflater= (LayoutInflater);
activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return objects.get(groupPosition).getObjects().get(childPosition);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
Object object= (Object) getChild(groupPosition, childPosition);
CustomExpandableListView subObjects=
(CustomExpandableListView) convertView;
if (convertView==null) {
subObjects= new CustomExpandableListView(activity);
}
Adapter2 adapter= new Adapter2(activity, object);
subObjects.setAdapter(adapter);
return subObjects;
}
@Override
public int getChildrenCount(int groupPosition) {
return objects.get(groupPosition).getObjects().size();
}
@Override
public Object getGroup(int groupPosition) {
return objects.get(groupPosition);
}
@Override
public int getGroupCount() {
return objects.size();
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
Object object= (Object) getGroup(groupPosition);
if (convertView==null) {
convertView= inflater.inflate(R.layout.listview_element, null);
}
TextView name= (TextView) convertView.findViewById(R.id.name);
name.setText(object.getName());
return convertView;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
The second adapter, which will also extend the BaseExpandableListAdapter, will be responsible for showing the second and third levels. Note that the first adapter constructs an X number of ExpandableListViews for each level 1 group, where X is the number of level 2 groups within each level 1 group.
class Adapter2 extends BaseExpandableListAdapter {
private Object object;
private LayoutInflater inflater;
private Activity activity;
public Adapter2(Activity activity, Object object) {
this.activity= activity;
this.object= object;
this.inflater= (LayoutInflater);
activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return object.getObjects().get(childPosition);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
Object object= (Object) getChild(0, childPosition);
if (convertView==null) {
convertView= inflater.inflate(R.layout.listview_element, null);
Resources r= activity.getResources();
float px40=
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 40, r.getDisplayMetrics());
convertView.setPadding(
convertView.getPaddingLeft() + (int) px40,
convertView.getPaddingTop(),
convertView.getPaddingRight(),
convertView.getPaddingBottom());
}
TextView name= (TextView) convertView.findViewById(R.id.name);
name.setText(object.getName());
return convertView;
}
@Override
public int getChildrenCount(int groupPosition) {
return object.getObjects().size();
}
@Override
public Object getGroup(int groupPosition) {
return object;
}
@Override
public int getGroupCount() {
return 1;
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
if (convertView==null) {
convertView= inflater.inflate(R.layout.listview_element, null);
Resources r = activity.getResources();
float px20 =
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 20, r.getDisplayMetrics());
convertView.setPadding(
convertView.getPaddingLeft() + (int) px20,
convertView.getPaddingTop(),
convertView.getPaddingRight(),
convertView.getPaddingBottom());
}
TextView name= (TextView) convertView.findViewById(R.id.name);
name.setText(object.getName());
return convertView;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
Working demo on Github.