一般来说在android里要实现树形菜单,都是用expandablelist(也有高手自己继承listview或者linearlayout来做),但是expandablelist一般只能实现2级树形菜单。本文所述实例也依然使用expandablelist,但是要实现的是3级树形菜单。
本文程序运行效果图如下图所示:
当用baseexpandablelistadapter来实现二级树形菜单时,父项(getgroupview())和子项(getchildview())都是使用textview。当要实现三级树形菜单时,子项(getchildview())就必须使用expandablelist了。另外还要定义结构体来方便调用三级树形的数据,二级树形菜单可以用如下:
1
2
3
4
|
static public class treenode{
object parent;
list<object> childs= new arraylist<object>();
}
|
三级树形菜单可以用如下,子项是二级树形菜单的结构体如下所示:
1
2
3
4
5
|
static public class supertreenode {
object parent;
//二级树形菜单的结构体
list<treeviewadapter.treenode> childs = new arraylist<treeviewadapter.treenode>();
}
|
实现三级树形菜单有两点要注意的:
1、第二级也是个树形菜单,因此必须在第二级项目展开/回收时设置足够的空间来完全显示二级树形菜单;
2、在实现三级树形菜单时,发现菜单的方法都是用不了(如onchildclicklistener、ongroupclicklistener等),因此要获得选中的数据就必须在外部定义好回调函数,然后在第二级生成二级树形菜单时回调这个外部函数。
此外还需要注意:本文在解决no.2关键点的时候,只能取得第三级选中的序号。而第一,第二级依然无法获取其序号。
main.xml源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<?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是主类,调用其他工具类,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
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是实现二级树形菜单的工具类,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
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,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
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程序设计有一定的帮助。