当前位置: 移动技术网 > IT编程>移动开发>Android > Android ExpandableListView双层嵌套实现三级树形菜单

Android ExpandableListView双层嵌套实现三级树形菜单

2019年08月01日  | 移动技术网IT编程  | 我要评论

r230清零图解,安徽选调生,穿越大唐绝代村姑

在android开发中,列表可以说是最常见的了,一般都是使用listview,当涉及到二维数组时,更多的使用到expandablelistview,然而当数据结构比较复杂时,就需要使用三级菜单或者更多级的菜单来显示,这就让人比较头疼了,最近做的项目就涉及到了三级菜单,遇到了不少问题,虽然不够完美,但是基本需求实现了,在此记录一下。(之前见过有人使用listview实现4级、5级甚至更多级菜单的,是在adapter的数据源里定义的结构,根据等级缩进左间距的倍数,链接地址找不到了,有兴趣的可以自己找找)

先上效果图:


简单介绍下重点,为了简便,把第一层expandablelistview称之为elistone,相应的adapter称之为adpone;第二层expandablelistview称之为elisttwo,相应的adapter称之为adptwo。

首先第一个要处理的问题是在adpone的getchildview方法中,需要对elisttwo的高度进行动态计算,因为elisttwo展开和关闭时高度是不一样的,所以要在elisttwo的setongroupexpandlistener和setongroupcollapselistener方法中做相应的处理:

/**
 * @author apathy、恒
 * 
 *   子expandablelistview展开时,因为group只有一项,所以子expandablelistview的总高度=
 *   (子expandablelistview的child数量 + 1 )* 每一项的高度
 * */
 elistview.setongroupexpandlistener(new ongroupexpandlistener() {
   @override
   public void ongroupexpand(int groupposition) {
 
 layoutparams lp = new layoutparams(viewgroup.layoutparams.match_parent, 
      (child.getchildnames().size() + 1)* (int) mcontext.getresources().getdimension(r.dimen.parent_expandable_list_height));
 elistview.setlayoutparams(lp);
 }
 });
 
 /**
 * @author apathy、恒
 * 
 * 子expandablelistview关闭时,此时只剩下group这一项,所以子expandablelistview的总高度即为一项的高度
 * */
 elistview.setongroupcollapselistener(new ongroupcollapselistener() {
 @override
 public void ongroupcollapse(int groupposition) {
 
 layoutparams lp = new layoutparams(
  viewgroup.layoutparams.match_parent, (int) mcontext
  .getresources().getdimension(
   r.dimen.parent_expandable_list_height));
 elistview.setlayoutparams(lp);
 }
 });

只展示菜单肯定不是我们的最终需求,我们一般需要点击菜单后进行相应的界面跳转或者数据处理,所以就需要获取所点击的菜单精确下标,获取方法很简单,只需要定义一个接口,在adpone的getchildview方法中回调即可:

/**
 * @author apathy、恒
 * 
 *   点击子expandablelistview子项时,调用回调接口
 * */
 elistview.setonchildclicklistener(new onchildclicklistener() {
 
 @override
 public boolean onchildclick(expandablelistview arg0, view arg1,
  int groupindex, int childindex, long arg4) {
 
 if (mtreeviewclicklistener != null) {
 
  mtreeviewclicklistener.onclickposition(groupposition,
  childposition, childindex);
 }
 return false;
 }
 });

下面是完整的代码:

mainactivity.java:

package com.heng.tree;
 
import java.util.arraylist;
 
import com.heng.tree.r;
import com.heng.tree.adapter.parentadapter;
import com.heng.tree.adapter.parentadapter.onchildtreeviewclicklistener;
import com.heng.tree.entity.childentity;
import com.heng.tree.entity.parententity;
 
import android.app.activity;
import android.content.context;
import android.graphics.color;
import android.os.bundle;
import android.widget.expandablelistview;
import android.widget.expandablelistview.ongroupexpandlistener;
import android.widget.toast;
 
/**
 * 
 * @author apathy、恒
 * 
 * <br/>
 * 
 * @email shexiaoheng@163.com
 * 
 * @blog
 * <a href='http://blog.csdn.net/shexiaoheng'>http://blog.csdn.net/shexiaoheng</a >
 * 
 * <br/>
 * <br/>
 * 
 * @detail 本demo为expandablelistview嵌套expandablelistview实现三级菜单的例子
 * 
 * #parentadapter.onchildtreeviewclicklistener
 * 
 * */
public class mainactivity extends activity implements ongroupexpandlistener,
 onchildtreeviewclicklistener {
 
 private context mcontext;
 
 private expandablelistview elist;
 
 private arraylist<parententity> parents;
 
 private parentadapter adapter;
 
 @override
 protected void oncreate(bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 
 mcontext = this;
 
 setcontentview(r.layout.activity_main);
 
 loaddata();
 
 initelist();
 
 }
 
 /**
 * @author apathy、恒
 * 
 *   初始化菜单数据源
 * */
 private void loaddata() {
 
 parents = new arraylist<parententity>();
 
 for (int i = 0; i < 10; i++) {
 
 parententity parent = new parententity();
 
 parent.setgroupname("父类父分组第" + i + "项");
 
 parent.setgroupcolor(getresources().getcolor(
  android.r.color.holo_red_light));
 
 arraylist<childentity> childs = new arraylist<childentity>();
 
 for (int j = 0; j < 8; j++) {
 
 childentity child = new childentity();
 
 child.setgroupname("子类父分组第" + j + "项");
 
 child.setgroupcolor(color.parsecolor("#ff00ff"));
 
 arraylist<string> childnames = new arraylist<string>();
 
 arraylist<integer> childcolors = new arraylist<integer>();
 
 for (int k = 0; k < 5; k++) {
 
  childnames.add("子类第" + k + "项");
 
  childcolors.add(color.parsecolor("#ff00ff"));
 
 }
 
 child.setchildnames(childnames);
 
 childs.add(child);
 
 }
 
 parent.setchilds(childs);
 
 parents.add(parent);
 
 }
 }
 
 /**
 * @author apathy、恒
 * 
 *   初始化expandablelistview
 * */
 private void initelist() {
 
 elist = (expandablelistview) findviewbyid(r.id.elist);
 
 elist.setongroupexpandlistener(this);
 
 adapter = new parentadapter(mcontext, parents);
 
 elist.setadapter(adapter);
 
 adapter.setonchildtreeviewclicklistener(this);
 
 }
 
 /**
 * @author apathy、恒
 * 
 *   点击子expandablelistview的子项时,回调本方法,根据下标获取值来做相应的操作
 * */
 @override
 public void onclickposition(int parentposition, int groupposition,
 int childposition) {
 // do something
 string childname = parents.get(parentposition).getchilds()
 .get(groupposition).getchildnames().get(childposition)
 .tostring();
 toast.maketext(
 mcontext,
 "点击的下标为: parentposition=" + parentposition
  + " groupposition=" + groupposition
  + " childposition=" + childposition + "\n点击的是:"
  + childname, toast.length_short).show();
 }
 
 /**
 * @author apathy、恒
 * 
 *   展开一项,关闭其他项,保证每次只能展开一项
 * */
 @override
 public void ongroupexpand(int groupposition) {
 for (int i = 0; i < parents.size(); i++) {
 if (i != groupposition) {
 elist.collapsegroup(i);
 }
 }
 }
 
}

parentadapter.java

package com.heng.tree.adapter;
 
import java.util.arraylist;
 
import android.content.context;
import android.view.layoutinflater;
import android.view.view;
import android.view.viewgroup;
import android.widget.baseexpandablelistadapter;
import android.widget.expandablelistview;
import android.widget.expandablelistview.onchildclicklistener;
import android.widget.expandablelistview.ongroupcollapselistener;
import android.widget.expandablelistview.ongroupexpandlistener;
import android.widget.abslistview.layoutparams;
import android.widget.textview;
 
import com.heng.tree.r;
import com.heng.tree.entity.childentity;
import com.heng.tree.entity.parententity;
 
/**
 * 
 * @author apathy、恒
 * 
 *   父类分组的适配器
 * 
 * <br/>
 * <br/>
 * 
 *   方法 {@link #getchildview(int, int, boolean, view, viewgroup)}<b><font
 *   color='#ff00ff' size='2'>极其重要</font></b>
 * 
 * */
 
public class parentadapter extends baseexpandablelistadapter {
 
 private context mcontext;// 上下文
 
 private arraylist<parententity> mparents;// 数据源
 
 private onchildtreeviewclicklistener mtreeviewclicklistener;// 点击子expandablelistview子项的监听
 
 public parentadapter(context context, arraylist<parententity> parents) {
 this.mcontext = context;
 this.mparents = parents;
 }
 
 @override
 public childentity getchild(int groupposition, int childposition) {
 return mparents.get(groupposition).getchilds().get(childposition);
 }
 
 @override
 public long getchildid(int groupposition, int childposition) {
 return childposition;
 }
 
 @override
 public int getchildrencount(int groupposition) {
 return mparents.get(groupposition).getchilds() != null ? mparents
 .get(groupposition).getchilds().size() : 0;
 }
 
 @override
 public view getchildview(final int groupposition, final int childposition,
 boolean isexpanded, view convertview, viewgroup parent) {
 
 final expandablelistview elistview = getexpandablelistview();
 
 arraylist<childentity> childs = new arraylist<childentity>();
 
 final childentity child = getchild(groupposition, childposition);
 
 childs.add(child);
 
 final childadapter childadapter = new childadapter(this.mcontext,
 childs);
 
 elistview.setadapter(childadapter);
 
 /**
 * @author apathy、恒
 * 
 *   点击子expandablelistview子项时,调用回调接口
 * */
 elistview.setonchildclicklistener(new onchildclicklistener() {
 
 @override
 public boolean onchildclick(expandablelistview arg0, view arg1,
  int groupindex, int childindex, long arg4) {
 
 if (mtreeviewclicklistener != null) {
 
  mtreeviewclicklistener.onclickposition(groupposition,
  childposition, childindex);
 }
 return false;
 }
 });
 
 
 /**
 * @author apathy、恒
 * 
 *   子expandablelistview展开时,因为group只有一项,所以子expandablelistview的总高度=
 *   (子expandablelistview的child数量 + 1 )* 每一项的高度
 * */
 elistview.setongroupexpandlistener(new ongroupexpandlistener() {
 @override
 public void ongroupexpand(int groupposition) {
 
 layoutparams lp = new layoutparams(
  viewgroup.layoutparams.match_parent, (child
  .getchildnames().size() + 1)
  * (int) mcontext.getresources().getdimension(
   r.dimen.parent_expandable_list_height));
 elistview.setlayoutparams(lp);
 }
 });
 
 /**
 * @author apathy、恒
 * 
 *   子expandablelistview关闭时,此时只剩下group这一项,
 *   所以子expandablelistview的总高度即为一项的高度
 * */
 elistview.setongroupcollapselistener(new ongroupcollapselistener() {
 @override
 public void ongroupcollapse(int groupposition) {
 
 layoutparams lp = new layoutparams(
  viewgroup.layoutparams.match_parent, (int) mcontext
  .getresources().getdimension(
   r.dimen.parent_expandable_list_height));
 elistview.setlayoutparams(lp);
 }
 });
 return elistview;
 
 }
 
 /**
 * @author apathy、恒
 * 
 *   动态创建子expandablelistview
 * */
 public expandablelistview getexpandablelistview() {
 expandablelistview mexpandablelistview = new expandablelistview(
 mcontext);
 layoutparams lp = new layoutparams(
 viewgroup.layoutparams.match_parent, (int) mcontext
  .getresources().getdimension(
  r.dimen.parent_expandable_list_height));
 mexpandablelistview.setlayoutparams(lp);
 mexpandablelistview.setdividerheight(0);// 取消group项的分割线
 mexpandablelistview.setchilddivider(null);// 取消child项的分割线
 mexpandablelistview.setgroupindicator(null);// 取消展开折叠的指示图标
 return mexpandablelistview;
 }
 
 @override
 public object getgroup(int groupposition) {
 return mparents.get(groupposition);
 }
 
 @override
 public int getgroupcount() {
 return mparents != null ? mparents.size() : 0;
 }
 
 @override
 public long getgroupid(int groupposition) {
 return groupposition;
 }
 
 @override
 public view getgroupview(int groupposition, boolean isexpanded,
 view convertview, viewgroup parent) {
 groupholder holder = null;
 if (convertview == null) {
 convertview = layoutinflater.from(mcontext).inflate(
  r.layout.parent_group_item, null);
 holder = new groupholder(convertview);
 convertview.settag(holder);
 } else {
 holder = (groupholder) convertview.gettag();
 }
 holder.update(mparents.get(groupposition));
 return convertview;
 }
 
 /**
 * @author apathy、恒
 * 
 *   holder优化
 * */
 class groupholder {
 
 private textview parentgrouptv;
 
 public groupholder(view v) {
 parentgrouptv = (textview) v.findviewbyid(r.id.parentgrouptv);
 }
 
 public void update(parententity model) {
 parentgrouptv.settext(model.getgroupname());
 parentgrouptv.settextcolor(model.getgroupcolor());
 }
 }
 
 @override
 public boolean hasstableids() {
 return false;
 }
 
 @override
 public boolean ischildselectable(int groupposition, int childposition) {
 return false;
 }
 
 /**
 * @author apathy、恒
 * 
 *   设置点击子expandablelistview子项的监听
 * */
 public void setonchildtreeviewclicklistener(
 onchildtreeviewclicklistener treeviewclicklistener) {
 this.mtreeviewclicklistener = treeviewclicklistener;
 }
 
 /**
 * @author apathy、恒
 * 
 *   点击子expandablelistview子项的回调接口
 * */
 public interface onchildtreeviewclicklistener {
 
 void onclickposition(int parentposition, int groupposition,
 int childposition);
 }
 
}

childadapter.java

package com.heng.tree.adapter;
 
import java.util.arraylist;
 
import com.heng.tree.r;
import com.heng.tree.entity.childentity;
 
import android.content.context;
import android.graphics.color;
import android.view.layoutinflater;
import android.view.view;
import android.view.viewgroup;
import android.widget.baseexpandablelistadapter;
import android.widget.textview;
 
/**
 * 
 * @author apathy、恒
 * 
 * <br/>
 * <br/>
 * 
 *   子类分组的适配器
 * 
 * <br/>
 * <br/>
 * 
 *   方法{@link #ischildselectable(int,int)} <b><font color='#ff00ff'
 *   size='2'>必须返回true</font></b>
 * 
 * */
public class childadapter extends baseexpandablelistadapter {
 
 private context mcontext;// 上下文
 
 private arraylist<childentity> mchilds;// 数据源
 
 public childadapter(context context, arraylist<childentity> childs) {
 this.mcontext = context;
 this.mchilds = childs;
 }
 
 @override
 public int getchildrencount(int groupposition) {
 return mchilds.get(groupposition).getchildnames() != null ? mchilds
 .get(groupposition).getchildnames().size() : 0;
 }
 
 @override
 public string getchild(int groupposition, int childposition) {
 if (mchilds.get(groupposition).getchildnames() != null
 && mchilds.get(groupposition).getchildnames().size() > 0)
 return mchilds.get(groupposition).getchildnames()
  .get(childposition).tostring();
 return null;
 }
 
 @override
 public long getchildid(int groupposition, int childposition) {
 return childposition;
 }
 
 @override
 public view getchildview(int groupposition, int childposition,
 boolean isexpanded, view convertview, viewgroup parent) {
 childholder holder = null;
 if (convertview == null) {
 convertview = layoutinflater.from(mcontext).inflate(
  r.layout.child_child_item, null);
 holder = new childholder(convertview);
 convertview.settag(holder);
 } else {
 holder = (childholder) convertview.gettag();
 }
 holder.update(getchild(groupposition, childposition));
 return convertview;
 }
 
 /**
 * @author apathy、恒
 * 
 *   holder优化
 * */
 class childholder {
 
 private textview childchildtv;
 
 public childholder(view v) {
 childchildtv = (textview) v.findviewbyid(r.id.childchildtv);
 }
 
 public void update(string str) {
 childchildtv.settext(str);
 childchildtv.settextcolor(color.parsecolor("#00ffff"));
 }
 }
 
 @override
 public object getgroup(int groupposition) {
 if (mchilds != null && mchilds.size() > 0)
 return mchilds.get(groupposition);
 return null;
 }
 
 @override
 public int getgroupcount() {
 return mchilds != null ? mchilds.size() : 0;
 }
 
 @override
 public long getgroupid(int groupposition) {
 return groupposition;
 }
 
 @override
 public view getgroupview(int groupposition, boolean isexpanded,
 view convertview, viewgroup parent) {
 groupholder holder = null;
 if (convertview == null) {
 convertview = layoutinflater.from(mcontext).inflate(
  r.layout.child_group_item, null);
 holder = new groupholder(convertview);
 convertview.settag(holder);
 } else {
 holder = (groupholder) convertview.gettag();
 }
 holder.update(mchilds.get(groupposition));
 return convertview;
 }
 
 /**
 * @author apathy、恒
 * 
 *   holder优化
 * */
 class groupholder {
 
 private textview childgrouptv;
 
 public groupholder(view v) {
 childgrouptv = (textview) v.findviewbyid(r.id.childgrouptv);
 }
 
 public void update(childentity model) {
 childgrouptv.settext(model.getgroupname());
 childgrouptv.settextcolor(model.getgroupcolor());
 }
 }
 
 @override
 public boolean hasstableids() {
 return false;
 }
 
 @override
 public boolean ischildselectable(int groupposition, int childposition) {
 /**
 * ==============================================
 * 此处必须返回true,否则无法响应子项的点击事件===============
 * ==============================================
 **/
 return true;
 }
 
}

clistadapter.java

package com.heng.tree.adapter;
 
import java.util.arraylist;
 
import com.heng.tree.r;
import com.heng.tree.entity.childentity;
 
import android.content.context;
import android.view.layoutinflater;
import android.view.view;
import android.view.viewgroup;
import android.widget.baseadapter;
import android.widget.textview;
 
/**
 * 
 * @author apathy、恒
 * 
 *   子类子类列表的适配器
 * 
 * */
public class clistadapter extends baseadapter {
 
 private context mcontext;
 private arraylist<childentity> mchilds;
 
 public clistadapter(context context, arraylist<childentity> childs) {
 this.mcontext = context;
 this.mchilds = childs;
 }
 
 @override
 public int getcount() {
 return mchilds != null ? mchilds.size() : 0;
 }
 
 @override
 public object getitem(int position) {
 if ((getcount() > 0) && (position > 0 && position < mchilds.size())) {
 return mchilds.get(position);
 }
 return null;
 }
 
 @override
 public long getitemid(int position) {
 return position;
 }
 
 @override
 public view getview(int position, view convertview, viewgroup parent) {
 holder holder = null;
 if (convertview == null) {
 convertview = layoutinflater.from(mcontext).inflate(
  r.layout.child_child_item, null);
 holder = new holder(convertview);
 convertview.settag(holder);
 } else {
 holder = (holder) convertview.gettag();
 }
 holder.update(mchilds.get(position).getgroupname());
 return convertview;
 }
 
 class holder {
 
 private textview tv;
 
 public holder(view v) {
 tv = (textview) v.findviewbyid(r.id.childchildtv);
 }
 
 public void update(string text) {
 tv.settext(text);
 }
 }
}

parententity.java

package com.heng.tree.entity;
 
import java.util.arraylist;
 
/**
 * 
 * @author apathy、恒
 * 
 *   子类分组的实体
 * 
 * */
 
public class parententity {
 
 private int groupcolor;
 
 private string groupname;
 
 private arraylist<childentity> childs;
 
 
 /* ==========================================================
 * ======================= get method =======================
 * ========================================================== */
 
 public int getgroupcolor() {
 return groupcolor;
 }
 
 public string getgroupname() {
 return groupname;
 }
 
 public arraylist<childentity> getchilds() {
 return childs;
 }
 
 /* ==========================================================
 * ======================= set method =======================
 * ========================================================== */
 
 public void setgroupcolor(int groupcolor) {
 this.groupcolor = groupcolor;
 }
 
 public void setgroupname(string groupname) {
 this.groupname = groupname;
 }
 
 public void setchilds(arraylist<childentity> childs) {
 this.childs = childs;
 }
 
}

childentity.java

package com.heng.tree.entity;
 
import java.util.arraylist;
 
/**
 * 
 * @author apathy、恒
 * 
 *   父类分组的实体
 * 
 * */
 
public class childentity {
 
 private int groupcolor;
 
 private string groupname;
 
 private arraylist<string> childnames;
 
 
 /* ==========================================================
 * ======================= get method =======================
 * ========================================================== */
 
 public int getgroupcolor() {
 return groupcolor;
 }
 
 public string getgroupname() {
 return groupname;
 }
 
 public arraylist<string> getchildnames() {
 return childnames;
 }
 
 /* ==========================================================
 * ======================= set method =======================
 * ========================================================== */
 
 public void setgroupcolor(int groupcolor) {
 this.groupcolor = groupcolor;
 }
 
 public void setgroupname(string groupname) {
 this.groupname = groupname;
 }
 
 public void setchildnames(arraylist<string> childnames) {
 this.childnames = childnames;
 }
 
}

activity_main.xml

<framelayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent" >
 
 <expandablelistview
  android:id="@+id/elist"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:groupindicator="@null" />
 
</framelayout>

parent_group_item.xml

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:paddingleft="@dimen/parent_expandable_list_group_padding_left" >
 
 <textview
  android:id="@+id/parentgrouptv"
  android:layout_width="wrap_content"
  android:layout_height="@dimen/parent_expandable_list_height"
  android:gravity="center_vertical" />
 
</relativelayout>

child_group_item.xml

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >
 
 <relativelayout
  android:layout_width="match_parent"
  android:layout_height="@dimen/parent_expandable_list_height" >
 
  <textview
   android:id="@+id/childgrouptv"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_centervertical="true"
   android:paddingleft="@dimen/child_expandable_list_group_padding_left" />
 </relativelayout>
 
</linearlayout>

child_child_item.xml

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >
 
 <relativelayout
  android:layout_width="match_parent"
  android:layout_height="@dimen/parent_expandable_list_height" >
 
  <textview
   android:id="@+id/childchildtv"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_centervertical="true"
   android:paddingleft="@dimen/child_expandable_list_child_padding_left" />
 </relativelayout>
 
</linearlayout>

dimens.xml

<resources>
 
 <!-- default screen margins, per the android design guidelines. -->
 <dimen name="parent_expandable_list_height">50dp</dimen>
 <dimen name="parent_expandable_list_group_padding_left">10dp</dimen>
 <dimen name="child_expandable_list_group_padding_left">40dp</dimen>
 <dimen name="child_expandable_list_child_padding_left">75dp</dimen>
 
</resources>

点此下载

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网