How to Display More Than 3- Levels of Expandable List View

How to display more than 3- levels of expandable List View?

I Found Solution and I am uploading all java class So check all java Or U can check this :

1: MainActivity.java

public class MainActivity extends Activity {

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

Object obj = new Object();
obj.children = new ArrayList<Object>();
for(int i = 0;i<Constant.state.length;i++)
{
Object root = new Object();
root.title = Constant.state[i];
root.children = new ArrayList<Object>();
for(int j=0;j<Constant.parent[i].length;j++)
{
Object parent = new Object();
parent.title=Constant.parent[i][j];
parent.children = new ArrayList<Object>();
for(int k=0;k<Constant.child[i][j].length;k++)
{
Object child = new Object();
child.title =Constant.child[i][j][k];
parent.children.add(child);
}
root.children.add(parent);
}
obj.children.add(root);
}

if (!obj.children.isEmpty()) {
final ExpandableListView elv = (ExpandableListView) findViewById(R.id.expList);

elv.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {

@Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {

return true; /* or false depending on what you need */;
}
});

ExpandableListView.OnGroupClickListener grpLst = new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView eListView, View view, int groupPosition,
long id) {

return true/* or false depending on what you need */;
}
};

ExpandableListView.OnChildClickListener childLst = new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView eListView, View view, int groupPosition,
int childPosition, long id) {

return true/* or false depending on what you need */;
}
};

ExpandableListView.OnGroupExpandListener grpExpLst = new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {

}
};

final RootAdapter adapter = new RootAdapter(this, obj, grpLst, childLst, grpExpLst);
elv.setAdapter(adapter);
}

}
}

2: Object.java

public class Object {
public String title; // use getters and setters instead
public List<Object> children; // same as above

public Object() {
children = new ArrayList<Object>();
}
}

3:RootAdapter.java

public class RootAdapter extends BaseExpandableListAdapter {

private Object root;

private final LayoutInflater inflater;

public class Entry {
public final CustExpListview cls;
public final SecondLevelAdapter sadpt;

public Entry(CustExpListview cls, SecondLevelAdapter sadpt) {
this.cls = cls;
this.sadpt = sadpt;
}
}

public Entry[] lsfirst;

public RootAdapter(Context context, Object root, ExpandableListView.OnGroupClickListener grpLst,
ExpandableListView.OnChildClickListener childLst, ExpandableListView.OnGroupExpandListener grpExpLst) {
this.root = root;
this.inflater = LayoutInflater.from(context);

lsfirst = new Entry[root.children.size()];

for (int i = 0; i < root.children.size(); i++) {
final CustExpListview celv = new CustExpListview(context);
SecondLevelAdapter adp = new SecondLevelAdapter(root.children.get(i),context);
celv.setAdapter(adp);
celv.setGroupIndicator(null);
celv.setOnChildClickListener(childLst);
celv.setOnGroupClickListener(grpLst);
celv.setOnGroupExpandListener(grpExpLst);

lsfirst[i] = new Entry(celv, adp);
}

}

@Override
public Object getChild(int groupPosition, int childPosition) {
return root.children.get(groupPosition);
}

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

@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
// second level list
return lsfirst[groupPosition].cls;
}

@Override
public int getChildrenCount(int groupPosition) {
return 1;
}

@Override
public Object getGroup(int groupPosition) {
return root.children.get(groupPosition);
}

@Override
public int getGroupCount() {
return root.children.size();
}

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

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

// first level

View layout = convertView;
GroupViewHolder holder;
final Object item = (Object) getGroup(groupPosition);

if (layout == null) {
layout = inflater.inflate(R.layout.item_root, parent, false);
holder = new GroupViewHolder();
holder.title = (TextView) layout.findViewById(R.id.itemRootTitle);
layout.setTag(holder);
} else {
holder = (GroupViewHolder) layout.getTag();
}

holder.title.setText(item.title.trim());

return layout;
}

private static class GroupViewHolder {
TextView title;
}

@Override
public boolean hasStableIds() {
return true;
}

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

4: SecondLevelAdapter.java

public class SecondLevelAdapter extends BaseExpandableListAdapter {

public Object child;
Context mContext;
LayoutInflater inflater;

public SecondLevelAdapter(Object child,Context context) {
this.child = child;
this.mContext=context;
inflater = LayoutInflater.from(mContext);
}

@Override
public Object getChild(int groupPosition, int childPosition) {
return child.children.get(groupPosition).children.get(childPosition);
}

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

// third level
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
View layout = convertView;
final Object item = (Object) getChild(groupPosition, childPosition);

ChildViewHolder holder;

if (layout == null) {
layout = inflater.inflate(R.layout.item_child, parent, false);

holder = new ChildViewHolder();
holder.title = (TextView) layout.findViewById(R.id.itemChildTitle);
layout.setTag(holder);
} else {
holder = (ChildViewHolder) layout.getTag();
}

holder.title.setText(item.title.trim());

return layout;
}

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

@Override
public Object getGroup(int groupPosition) {
return child.children.get(groupPosition);
}

@Override
public int getGroupCount() {
return child.children.size();
}

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

// Second level
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
View layout = convertView;
ViewHolder holder;

final Object item = (Object) getGroup(groupPosition);

if (layout == null) {
layout = inflater.inflate(R.layout.item_parent, parent, false);
holder = new ViewHolder();
holder.title = (TextView) layout.findViewById(R.id.itemParentTitle);
layout.setTag(holder);
} else {
holder = (ViewHolder) layout.getTag();
}

holder.title.setText(item.title.trim());

return layout;
}

@Override
public void registerDataSetObserver(DataSetObserver observer) {
super.registerDataSetObserver(observer);
}

@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
Log.d("SecondLevelAdapter", "Unregistering observer");
if (observer != null) {
super.unregisterDataSetObserver(observer);
}
}

@Override
public boolean hasStableIds() {
return true;
}

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

private static class ViewHolder {
TextView title;
}

private static class ChildViewHolder {
TextView title;
}

}

5 Constant.java

public class Constant {
static String[] state = {"A","B","C"};
static String[][] parent = {
{"aa","bb","cc","dd","ee"},
{"ff","gg","hh","ii","jj"},
{"kk","ll","mm","nn","oo"}
};

static String[][][] child = {
{
{"aaa","aab","aac","aad","aae"},
{"bba","bbb","bbc","bbd","bbe"},
{"cca","ccb","ccc","ccd","cce","ccf","ccg"},
{"dda","ddb","dddc","ddd","dde","ddf"},
{"eea","eeb","eec"}
},
{
{"ffa","ffb","ffc","ffd","ffe"},
{"gga","ggb","ggc","ggd","gge"},
{"hha","hhb","hhc","hhd","hhe","hhf","hhg"},
{"iia","iib","iic","iid","iie","ii"},
{"jja","jjb","jjc","jjd"}
},
{
{"kka","kkb","kkc","kkd","kke"},
{"lla","llb","llc","lld","lle"},
{"mma","mmb","mmc","mmd","mme","mmf","mmg"},
{"nna","nnb","nnc","nnd","nne","nnf"},
{"ooa","oob"}
}
};
}

5: item_parent.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="10dp" >

<TextView
android:id="@+id/itemParentTitle"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:background="#5ccccc"
android:padding="2dp"
android:textColor="#006363"
android:textSize="20sp" />

<ImageView
android:id="@+id/itemParentImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>

Android: Multi-level ExpandableListView displaying children multiple times

Found the answer here: https://stackoverflow.com/a/35208411/5004391

I don't really understand why but I had to hardcode getChildrenCount(int groupPosition) for the Root level to return 1, as opposed to the actual number of children. In my app's other ExpandableListViews I always return the number of children and it works as expected.

Multi-level ExpandableListView in Android

I believe the problem is in your getChildView() method:

    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {

convertView = inflater.inflate(R.layout.catitem, parent, false);
TextView textView_catName = (TextView)convertView.findViewById(R.id.textView_catName);
Category current = categories.get(groupPosition).childs.get(childPosition);
textView_catName.setText(groupPosition + " , " + childPosition);

if(current.childs.size() > 0 ) {
ExpandableListView elv = new ExpandableListView(context);
elv.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.WRAP_CONTENT, AbsListView.LayoutParams.WRAP_CONTENT));
elv.setAdapter(new CatAdapter(context, current.childs));
((ViewGroup)convertView).addView(elv);
}

return convertView;
}

When you encounter an 'expandable' child, you are still inflating R.layout.catitem and adding your new elv to it. Since the catitem is a RelativeLayout and you don't add any parameters for alignment, each view is placed at the top-left corner, overlaying whatever else is there.

You may want to try changing R.layout.catitem to have a vertical LinearLayout as its root. This should prevent them from overlapping the child's title, but I can't guarantee that the children's children will not still overlap. It's an easy change, though, and worth a shot.


Also, from the docs for ExpandableListView:

Note: You cannot use the value wrap_content for the android:layout_height attribute of a ExpandableListView in XML if the parent's size is also not strictly specified (for example, if the parent were ScrollView you could not specify wrap_content since it also can be any length. However, you can use wrap_content if the ExpandableListView parent has a specific size, such as 100 pixels.

That says "in XML", so I'm not sure if it means to apply to code or not. It seems to me that they'd use the same mechanism, so it might be worth looking into. I'm not sure how you'd go about setting a maximum size for the parent. You may be able to measure the size of one item, and multiply by the number of children. You'd have to take margins/separators into account, so it may not be simple.


If that doesn't work, you may need to roll your own ViewGroup directly. It shouldn't be too hard to implement it from scratch, just don't forget to try to take advantage of view recycling(which your current method doesn't do anyway).

3 level ExpandableListView Android

The problem is for every row of -->Second it is a whole ExpandableListView,which contains 5 Groups. And as the height of the current parent group won't expand automatically for the child ExpandableListView. You can't see the opened children list: third.

To Fix the problem, there are a few changes to be made:

  1. Change the GroupCount of SecondLevelAdapter from 5 to 1:

    public override int GroupCount
    {
    get
    {
    //return 5;
    return 1;//Change GroupCount to 1
    }
    }
  2. You need to change the height of every second level ExpandableListView manually. This can be done by implementing GroupExpand and GroupCollapse events:

    ParentView.cs:

    public override View GetChildView(int groupPosition, int childPosition, bool isLastChild, View convertView, ViewGroup parent)
    {
    var SecondLevelexplv = new CustExpListview(Application.Context);
    SecondLevelexplv.SetAdapter(new SecondLevelAdapter(context));
    SecondLevelexplv.SetGroupIndicator(null);
    SecondLevelexplv.GroupExpand += SecondLevelexplv_GroupExpand;
    SecondLevelexplv.GroupCollapse += SecondLevelexplv_GroupCollapse;
    return SecondLevelexplv;
    }

    private void SecondLevelexplv_GroupCollapse(object sender, ExpandableListView.GroupCollapseEventArgs e)
    {
    AbsListView.LayoutParams lp = new AbsListView.LayoutParams(AbsListView.LayoutParams.MatchParent, 70);
    (sender as CustExpListview).LayoutParameters = lp;
    }

    private void SecondLevelexplv_GroupExpand(object sender, ExpandableListView.GroupExpandEventArgs e)
    {
    //expand the group and the height is the `children count` * `unit height`
    AbsListView.LayoutParams lp = new AbsListView.LayoutParams(AbsListView.LayoutParams.MatchParent, 70 * 5);
    (sender as CustExpListview).LayoutParameters = lp;
    }

Thus, it will work correctly:

Sample Image

Issue with Expanding Multi-Level ExpandableListView

I ended up using a multi level ExpandableListView adapter from another post in stackoverflow. Unfortunately I just can't find the link anymore so I'll just post my code here.

Top Level of the ExpandableListView adapter.

RootAdapter.java:

public class RootAdapter extends BaseExpandableListAdapter {

private Object root;

private final LayoutInflater inflater;

public class Entry {
public final CustExpListview cls;
public final SecondLevelAdapter sadpt;

public Entry(CustExpListview cls, SecondLevelAdapter sadpt) {
this.cls = cls;
this.sadpt = sadpt;
}
}

public Entry[] lsfirst;

// you can change the constructor depending on which listeners you wan't to use.
public RootAdapter(Context context, Object root, ExpandableListView.OnGroupClickListener grpLst,
ExpandableListView.OnChildClickListener childLst, ExpandableListView.OnGroupExpandListener grpExpLst) {
this.root = root;
this.inflater = LayoutInflater.from(context);

lsfirst = new Entry[root.children.size()];

for (int i = 0; i < root.children.size(); i++) {
final CustExpListview celv = new CustExpListview(context);
SecondLevelAdapter adp = new SecondLevelAdapter(root.children.get(i));
celv.setAdapter(adp);
celv.setGroupIndicator(null);
celv.setOnChildClickListener(childLst);
celv.setOnGroupClickListener(grpLst);
celv.setOnGroupExpandListener(grpExpLst);

lsfirst[i] = new Entry(celv, adp);
}

}

@Override
public Object getChild(int groupPosition, int childPosition) {
return 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) {
// second level list
return lsfirst[groupPosition].cls;
}

@Override
public int getChildrenCount(int groupPosition) {
return 1;
}

@Override
public Object getGroup(int groupPosition) {
return root.children.get(groupPosition);
}

@Override
public int getGroupCount() {
return root.children.size();
}

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

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

// first level

View layout = convertView;
GroupViewHolder holder;
final Object item = (Object) getGroup(groupPosition);

if (layout == null) {
layout = inflater.inflate(R.layout.item_root, parent, false);
holder = new GroupViewHolder();
holder.title = (TextView) layout.findViewById(R.id.itemRootTitle);
layout.setTag(holder);
} else {
holder = (GroupViewHolder) layout.getTag();
}

holder.title.setText(item.title.trim());

return layout;
}

private static class GroupViewHolder {
TextView title;
}

@Override
public boolean hasStableIds() {
return true;
}

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

Custom ExpandableListView with the solution to items sometimes not being displayed. There is also a workaround to a known bug for IllegalArgumentException being called when destroying the view (by pressing the back button essentially).

CustExpListview.java:

public class CustExpListview extends ExpandableListView {

public CustExpListview(Context context) {
super(context);

}

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// the value (2000) should not be fixed and be calculated
// as follows: cell_height x root_items_count x root_items_children_count
heightMeasureSpec = MeasureSpec.makeMeasureSpec(2000, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

@Override
protected void onDetachedFromWindow() {
try {
super.onDetachedFromWindow();
} catch (IllegalArgumentException e) {
// TODO: Workaround for http://code.google.com/p/android/issues/detail?id=22751
}
}
}

Finally, the code to the last level adapter.

public class SecondLevelAdapter extends BaseExpandableListAdapter {

public Object child;

public SecondLevelAdapter(Object child) {
this.child = child;
}

@Override
public Object getChild(int groupPosition, int childPosition) {
return child.children.get(groupPosition).children.get(childPosition);
}

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

// third level
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
View layout = convertView;
final Object item = (Object) getChild(groupPosition, childPosition);

ChildViewHolder holder;

if (layout == null) {
layout = inflater.inflate(R.layout.item_child, parent, false);

holder = new ChildViewHolder();
holder.title = (TextView) layout.findViewById(R.id.itemChildTitle);
layout.setTag(holder);
} else {
holder = (ChildViewHolder) layout.getTag();
}

holder.title.setText(item.title.trim());

return layout;
}

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

@Override
public Object getGroup(int groupPosition) {
return child.children.get(groupPosition);
}

@Override
public int getGroupCount() {
return child.children.size();
}

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

// Second level
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
View layout = convertView;
ViewHolder holder;

final Object item = (Object) getGroup(groupPosition);

if (layout == null) {
layout = inflater.inflate(R.layout.item_parent, parent, false);
holder = new ViewHolder();
holder.title = (TextView) layout.findViewById(R.id.itemParentTitle);
layout.setTag(holder);
} else {
holder = (ViewHolder) layout.getTag();
}

holder.title.setText(item.title.trim());

return layout;
}

@Override
public void registerDataSetObserver(DataSetObserver observer) {
super.registerDataSetObserver(observer);
}

@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
Log.d("SecondLevelAdapter", "Unregistering observer");
if (observer != null) {
super.unregisterDataSetObserver(observer);
}
}

@Override
public boolean hasStableIds() {
return true;
}

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

private static class ViewHolder {
TextView title;
}

private static class ChildViewHolder {
TextView title;
}

}

I hope this helps!!!

Update

This is an example of how I call the above adapter.

MainActivity:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

final List<Object> objects = yourItems;
if (!objects.isEmpty()) {
final ExpandableListView elv = (ExpandableListView) findViewById(R.id.yourExpandableListView);
/* Item click listeners below */

// First level items in the ExpandableListView
elv.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView eListView, View view, int groupPosition,
long id) {
// TODO: whatever you need
return false /* or true depending on what you need */;
}
});

// Second level items in the ExpandableListView
ExpandableListView.OnGroupClickListener grpLst = new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView eListView, View view, int groupPosition,
long id) {
// TODO: whatever you need
return false /* or true depending on what you need */;
}
};

// Third (and last) level items in the ExpandableListView
ExpandableListView.OnChildClickListener childLst = new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView eListView, View view, int groupPosition,
int childPosition, long id) {
// TODO: whatever you need
return false /* or true depending on what you need */;
}
};

ExpandableListView.OnGroupExpandListener grpExpLst = new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
/* this one is not required of course, you can delete it from the RootAdapter Constructor
* it is just an example as to how to implement Listeners on the second level items */
}
};

final RootAdapter adapter = new RootAdapter(this, objects, grpLst, childLst, grpExpLst);
elv.setAdapter(adapter);
}
}

This is how my class Object would look like.

Object.java:

public class Object {
public String title; // use getters and setters instead
public List<Object> children; // same as above

public Object() {
children = new ArrayList<Object>();
}
}


Related Topics



Leave a reply



Submit