Android提高之多级树形菜单的实现方法
一般来说在android里要实现树形菜单,都是用expandablelist(也有高手自己继承listview或者linearlayout来做),但是expandablelist一般只能实现2级树形菜单。本文所述实例也依然使用expandablelist,但是要实现的是3级树形菜单。
本文程序运行效果图如下图所示:
当用baseexpandablelistadapter来实现二级树形菜单时,父项(getgroupview())和子项(getchildview())都是使用textview。当要实现三级树形菜单时,子项(getchildview())就必须使用expandablelist了。另外还要定义结构体来方便调用三级树形的数据,二级树形菜单可以用如下:
static public class treenode{ object parent; list<object> childs=new arraylist<object>(); }
三级树形菜单可以用如下,子项是二级树形菜单的结构体如下所示:
static public class supertreenode { object parent; //二级树形菜单的结构体 list<treeviewadapter.treenode> childs = new arraylist<treeviewadapter.treenode>(); }
实现三级树形菜单有两点要注意的:
1、第二级也是个树形菜单,因此必须在第二级项目展开/回收时设置足够的空间来完全显示二级树形菜单;
2、在实现三级树形菜单时,发现菜单的方法都是用不了(如onchildclicklistener、ongroupclicklistener等),因此要获得选中的数据就必须在外部定义好回调函数,然后在第二级生成二级树形菜单时回调这个外部函数。
此外还需要注意:本文在解决no.2关键点的时候,只能取得第三级选中的序号。而第一,第二级依然无法获取其序号。
main.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="fill_parent"> <linearlayout android:id="@+id/linearlayout01" android:layout_width="wrap_content" android:layout_height="wrap_content"> <button android:layout_height="wrap_content" android:text="两层结构" android:layout_width="160dip" android:id="@+id/btnnormal"></button> <button android:layout_height="wrap_content" android:text="三层结构" android:layout_width="160dip" android:id="@+id/btnsuper"></button> </linearlayout> <expandablelistview android:id="@+id/expandablelistview01" android:layout_width="fill_parent" android:layout_height="fill_parent"></expandablelistview> </linearlayout>
testexpandablelist.java是主类,调用其他工具类,源码如下:
package com.testexpandablelist; import java.util.list; import android.app.activity; import android.os.bundle; import android.util.log; import android.view.view; import android.widget.button; import android.widget.expandablelistview; import android.widget.expandablelistview.onchildclicklistener; import android.widget.toast; public class testexpandablelist extends activity { /** called when the activity is first created. */ expandablelistview expandablelist; treeviewadapter adapter; supertreeviewadapter superadapter; button btnnormal,btnsuper; // sample data set. children[i] contains the children (string[]) for groups[i]. public string[] groups = { "xxxx好友", "xxxx同学", "xxxxx女人"}; public string[][] child= { { "a君", "b君", "c君", "d君" }, { "同学甲", "同学乙", "同学丙"}, { "御姐", "萝莉" } }; public string[] parent = { "xxxx好友", "xxxx同学"}; public string[][][] child_grandson= { {{"a君"}, {"aa","aaa"}}, {{"b君"}, {"bbb","bbbb","bbbbb"}}, {{"c君"}, {"ccc","cccc"}}, {{"d君"}, {"ddd","dddd","ddddd"}}, }; @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); this.settitle("expandablelistview练习----hellogv"); btnnormal=(button)this.findviewbyid(r.id.btnnormal); btnnormal.setonclicklistener(new clickevent()); btnsuper=(button)this.findviewbyid(r.id.btnsuper); btnsuper.setonclicklistener(new clickevent()); adapter=new treeviewadapter(this,treeviewadapter.paddingleft>>1); superadapter=new supertreeviewadapter(this,stvclickevent); expandablelist=(expandablelistview) testexpandablelist.this.findviewbyid(r.id.expandablelistview01); } class clickevent implements view.onclicklistener{ @override public void onclick(view v) { adapter.removeall(); adapter.notifydatasetchanged(); superadapter.removeall(); superadapter.notifydatasetchanged(); if(v==btnnormal) { list<treeviewadapter.treenode> treenode = adapter.gettreenode(); for(int i=0;i<groups.length;i++) { treeviewadapter.treenode node=new treeviewadapter.treenode(); node.parent=groups[i]; for(int ii=0;ii<child[i].length;ii++) { node.childs.add(child[i][ii]); } treenode.add(node); } adapter.updatetreenode(treenode); expandablelist.setadapter(adapter); expandablelist.setonchildclicklistener(new onchildclicklistener(){ @override public boolean onchildclick(expandablelistview arg0, view arg1, int parent, int children, long arg4) { string str="parent id:"+string.valueof(parent)+",children id:"+string.valueof(children); toast.maketext(testexpandablelist.this, str, 300).show(); return false; } }); } else if(v==btnsuper){ list<supertreeviewadapter.supertreenode> supertreenode = superadapter.gettreenode(); for(int i=0;i<parent.length;i++)//第一层 { supertreeviewadapter.supertreenode supernode=new supertreeviewadapter.supertreenode(); supernode.parent=parent[i]; //第二层 for(int ii=0;ii<child_grandson.length;ii++) { treeviewadapter.treenode node=new treeviewadapter.treenode(); node.parent=child_grandson[ii][0][0];//第二级菜单的标题 for(int iii=0;iii<child_grandson[ii][1].length;iii++)//第三级菜单 { node.childs.add(child_grandson[ii][1][iii]); } supernode.childs.add(node); } supertreenode.add(supernode); } superadapter.updatetreenode(supertreenode); expandablelist.setadapter(superadapter); } } } /** * 三级树形菜单的事件不再可用,本函数由三级树形菜单的子项(二级菜单)进行回调 */ onchildclicklistener stvclickevent=new onchildclicklistener(){ @override public boolean onchildclick(expandablelistview parent, view v, int groupposition, int childposition, long id) { string str="parent id:"+string.valueof(groupposition)+",children id:"+string.valueof(childposition); toast.maketext(testexpandablelist.this, str, 300).show(); return false; } }; }
treeviewadapter.java是实现二级树形菜单的工具类,源码如下:
package com.testexpandablelist; import java.util.arraylist; import java.util.list; import android.content.context; import android.util.log; import android.view.gravity; import android.view.view; import android.view.viewgroup; import android.widget.abslistview; import android.widget.baseexpandablelistadapter; import android.widget.textview; public class treeviewadapter extends baseexpandablelistadapter{ public static final int itemheight=48;//每项的高度 public static final int paddingleft=36;//每项的高度 private int mypaddingleft=0;//如果是由supertreeview调用,则作为子项需要往右移 static public class treenode{ object parent; list<object> childs=new arraylist<object>(); } list<treenode> treenodes = new arraylist<treenode>(); context parentcontext; public treeviewadapter(context view,int mypaddingleft) { parentcontext=view; this.mypaddingleft=mypaddingleft; } public list<treenode> gettreenode() { return treenodes; } public void updatetreenode(list<treenode> nodes) { treenodes=nodes; } public void removeall() { treenodes.clear(); } public object getchild(int groupposition, int childposition) { return treenodes.get(groupposition).childs.get(childposition); } public int getchildrencount(int groupposition) { return treenodes.get(groupposition).childs.size(); } static public textview gettextview(context context) { abslistview.layoutparams lp = new abslistview.layoutparams( viewgroup.layoutparams.fill_parent, itemheight); textview textview = new textview(context); textview.setlayoutparams(lp); textview.setgravity(gravity.center_vertical | gravity.left); return textview; } public view getchildview(int groupposition, int childposition, boolean islastchild, view convertview, viewgroup parent) { textview textview = gettextview(this.parentcontext); textview.settext(getchild(groupposition, childposition).tostring()); textview.setpadding(mypaddingleft+paddingleft, 0, 0, 0); return textview; } public view getgroupview(int groupposition, boolean isexpanded, view convertview, viewgroup parent) { textview textview = gettextview(this.parentcontext); textview.settext(getgroup(groupposition).tostring()); textview.setpadding(mypaddingleft+(paddingleft>>1), 0, 0, 0); return textview; } public long getchildid(int groupposition, int childposition) { return childposition; } public object getgroup(int groupposition) { return treenodes.get(groupposition).parent; } public int getgroupcount() { return treenodes.size(); } public long getgroupid(int groupposition) { return groupposition; } public boolean ischildselectable(int groupposition, int childposition) { return true; } public boolean hasstableids() { return true; } }
supertreeviewadapter.java是实现三级树形菜单的工具类,会用到treeviewadapter.java,源码如下:
package com.testexpandablelist; import java.util.arraylist; import java.util.list; import com.testexpandablelist.treeviewadapter.treenode; import android.content.context; import android.view.view; import android.view.viewgroup; import android.widget.abslistview; 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.textview; public class supertreeviewadapter extends baseexpandablelistadapter { static public class supertreenode { object parent; //二级树形菜单的结构体 list<treeviewadapter.treenode> childs = new arraylist<treeviewadapter.treenode>(); } private list<supertreenode> supertreenodes = new arraylist<supertreenode>(); private context parentcontext; private onchildclicklistener stvclickevent;//外部回调函数 public supertreeviewadapter(context view,onchildclicklistener stvclickevent) { parentcontext = view; this.stvclickevent=stvclickevent; } public list<supertreenode> gettreenode() { return supertreenodes; } public void updatetreenode(list<supertreenode> node) { supertreenodes = node; } public void removeall() { supertreenodes.clear(); } public object getchild(int groupposition, int childposition) { return supertreenodes.get(groupposition).childs.get(childposition); } public int getchildrencount(int groupposition) { return supertreenodes.get(groupposition).childs.size(); } public expandablelistview getexpandablelistview() { abslistview.layoutparams lp = new abslistview.layoutparams( viewgroup.layoutparams.fill_parent, treeviewadapter.itemheight); expandablelistview supertreeview = new expandablelistview(parentcontext); supertreeview.setlayoutparams(lp); return supertreeview; } /** * 三层树结构中的第二层是一个expandablelistview */ public view getchildview(int groupposition, int childposition, boolean islastchild, view convertview, viewgroup parent) { // 是 final expandablelistview treeview = getexpandablelistview(); final treeviewadapter treeviewadapter = new treeviewadapter(this.parentcontext,0); list<treenode> tmp = treeviewadapter.gettreenode();//临时变量取得treeviewadapter的treenode集合,可为空 final treenode treenode=(treenode) getchild(groupposition, childposition); tmp.add(treenode); treeviewadapter.updatetreenode(tmp); treeview.setadapter(treeviewadapter); //关键点:取得选中的二级树形菜单的父子节点,结果返回给外部回调函数 treeview.setonchildclicklistener(this.stvclickevent); /** * 关键点:第二级菜单展开时通过取得节点数来设置第三级菜单的大小 */ treeview.setongroupexpandlistener(new ongroupexpandlistener() { @override public void ongroupexpand(int groupposition) { abslistview.layoutparams lp = new abslistview.layoutparams( viewgroup.layoutparams.fill_parent, (treenode.childs.size()+1)*treeviewadapter.itemheight + 10); treeview.setlayoutparams(lp); } }); /** * 第二级菜单回收时设置为标准item大小 */ treeview.setongroupcollapselistener(new ongroupcollapselistener() { @override public void ongroupcollapse(int groupposition) { abslistview.layoutparams lp = new abslistview.layoutparams(viewgroup.layoutparams.fill_parent, treeviewadapter.itemheight); treeview.setlayoutparams(lp); } }); treeview.setpadding(treeviewadapter.paddingleft, 0, 0, 0); return treeview; } /** * 三级树结构中的首层是textview,用于作为title */ public view getgroupview(int groupposition, boolean isexpanded, view convertview, viewgroup parent) { textview textview = treeviewadapter.gettextview(this.parentcontext); textview.settext(getgroup(groupposition).tostring()); textview.setpadding(treeviewadapter.paddingleft, 0, 0, 0); return textview; } public long getchildid(int groupposition, int childposition) { return childposition; } public object getgroup(int groupposition) { return supertreenodes.get(groupposition).parent; } public int getgroupcount() { return supertreenodes.size(); } public long getgroupid(int groupposition) { return groupposition; } public boolean ischildselectable(int groupposition, int childposition) { return true; } public boolean hasstableids() { return true; } }
总结,使用expandablelist实现三级树形菜单时有些bug不好解决,而且定义三维数组的时候也要倍加小心!所以尽量把数据化简来使用二级树形菜单。
希望本文所述代码对大家进行android程序设计有一定的帮助。
上一篇: 郑一嫂是怎么当上海盗的,为何最后成了林则徐的手下?
下一篇: 凤尾菜是不是油麦菜