在Android里要实现树形菜单,都是用ExpandableList(也有高手自己继承ListView或者LinearLayout来做),但是ExpandableList一般只能实现2级树形菜单......本文也依然使用ExpandableList,但是要实现的是3级树形菜单。本文程序运行效果图:
当用BaseExpandableListAdapter来实现二级树形菜单时,父项(getGroupView())和子项(getChildView())都是使用TextView。当要实现三级树形菜单时,子项(getChildView())就必须使用ExpandableList了.......另外还要定义结构体来方便调用三级树形的数据,二级树形菜单可以用如下:
Java代码
1. static public class TreeNode{
2. Object parent;
3. new ArrayList();
4. }
三级树形菜单可以用如下,子项是二级树形菜单的结构体:
Java代码
1. static public class SuperTreeNode {
2. Object parent;
3. //二级树形菜单的结构体
4. new ArrayList[tr]();
5. }
实现三级树形菜单有两点要注意的:1、第二级也是个树形菜单,因此必须在第二级项目展开/回收时设置足够的空间来完全显示二级树形菜单;2、在实现三级树形菜单时,发现菜单的方法都是用不了(如OnChildClickListener、OnGroupClickListener等),因此要获得选中的数据就必须在外部定义好回调函数,然后在第二级生成二级树形菜单时回调这个外部函数。PS:本文在解决No.2关键点的时候,只能取得第三级选中的序号.....而第一,第二级依然无法获取其序号。main.xml源码如下:
XML/HTML代码
1. <linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
2. android:orientation="vertical" android:layout_width="fill_parent"
3. android:layout_height="fill_parent">
4. <linearlayout android:id="@+id/LinearLayout01"
5. android:layout_width="wrap_content" android:layout_height="wrap_content">
6. <button android:layout_height="wrap_content" android:text="两层结构"
7. android:layout_width="160dip" android:id="@+id/btnNormal">
8. <button android:layout_height="wrap_content" android:text="三层结构"
9. android:layout_width="160dip" android:id="@+id/btnSuper">
10.
11. <expandablelistview android:id="@+id/ExpandableListView01"
12. android:layout_width="fill_parent" android:layout_height="fill_parent">
testExpandableList.java是主类,调用其他工具类,源码如下:
Java代码
1. package com.testExpandableList;
2.
3.
4. import java.util.List;
5. import android.app.Activity;
6. import android.os.Bundle;
7. import android.util.Log;
8. import android.view.View;
9. import android.widget.Button;
10. import android.widget.ExpandableListView;
11. import android.widget.ExpandableListView.OnChildClickListener;
12. import android.widget.Toast;
13.
14. public class testExpandableList extends Activity {
15. /** Called when the activity is first created. */
16. ExpandableListView expandableList;
17. TreeViewAdapter adapter;
18. SuperTreeViewAdapter superAdapter;
19. Button btnNormal,btnSuper;
20. // Sample data set. children[i] contains the children (String[]) for groups[i].
21. public String[] groups = { "xxxx好友", "xxxx同学", "xxxxx女人"};
22. public String[][] child= {
23. "A君", "B君", "C君", "D君" },
24. "同学甲", "同学乙", "同学丙"},
25. "御姐", "萝莉" }
26. };
27.
28. public String[] parent = { "xxxx好友", "xxxx同学"};
29. public String[][][] child_grandson= {
30. "A君"},
31. "AA","AAA"}},
32. "B君"},
33. "BBB","BBBB","BBBBB"}},
34. "C君"},
35. "CCC","CCCC"}},
36. "D君"},
37. "DDD","DDDD","DDDDD"}},
38. };
39.
40. @Override
41. public void onCreate(Bundle savedInstanceState) {
42. super.onCreate(savedInstanceState);
43. setContentView(R.layout.main);
44. this.setTitle("ExpandableListView练习----hellogv");
45. this.findViewById(R.id.btnNormal);
46. new ClickEvent());
47. this.findViewById(R.id.btnSuper);
48. new ClickEvent());
49. new TreeViewAdapter(this,TreeViewAdapter.PaddingLeft>>1);
50. new SuperTreeViewAdapter(this,stvClickEvent);
51. this.findViewById(R.id.ExpandableListView01);
52. }
53.
54. class ClickEvent implements View.OnClickListener{
55.
56. @Override
57. public void onClick(View v) {
58. adapter.RemoveAll();
59. adapter.notifyDataSetChanged();
60. superAdapter.RemoveAll();
61. superAdapter.notifyDataSetChanged();
62.
63. if(v==btnNormal)
64. {
65. List[tr] treeNode = adapter.GetTreeNode();
66. for(int i=0;i<groups.length;i++)
67. {
68. new TreeViewAdapter.TreeNode();
69. node.parent=groups[i];
70. for(int ii=0;ii<child[i].length;ii++)
71. {
72. node.childs.add(child[i][ii]);
73. }
74. treeNode.add(node);
75. }
76.
77. adapter.UpdateTreeNode(treeNode);
78. expandableList.setAdapter(adapter);
79. new OnChildClickListener(){
80.
81. @Override
82. public boolean onChildClick(ExpandableListView arg0, View arg1,
83. int parent, int children, long arg4) {
84.
85. "parent id:"+String.valueOf(parent)+",children id:"+String.valueOf(children);
86. this, str, 300).show();
87. return false;
88. }
89. });
90. }
91. else if(v==btnSuper){
92. List superTreeNode = superAdapter.GetTreeNode();
93. for(int i=0;i<parent.length;i++) 第一层
94. {
95. new SuperTreeViewAdapter.SuperTreeNode();
96. superNode.parent=parent[i];
97.
98. //第二层
99. for(int ii=0;ii<child_grandson.length;ii++)
100. {
101. new TreeViewAdapter.TreeNode();
102. 0][0];//第二级菜单的标题
103.
104. for(int iii=0;iii<child_grandson[ii][1].length;iii++) 第三级菜单
105. {
106. 1][iii]);
107. }
108. superNode.childs.add(node);
109. }
110. superTreeNode.add(superNode);
111.
112. }
113. superAdapter.UpdateTreeNode(superTreeNode);
114. expandableList.setAdapter(superAdapter);
115. }
116. }
117. }
118.
119. /**
120. * 三级树形菜单的事件不再可用,本函数由三级树形菜单的子项(二级菜单)进行回调
121. */
122. new OnChildClickListener(){
123.
124. @Override
125. public boolean onChildClick(ExpandableListView parent,
126. int groupPosition, int childPosition,
127. long id) {
128. "parent id:"+String.valueOf(groupPosition)+",children id:"+String.valueOf(childPosition);
129. this, str, 300).show();
130.
131. return false;
132. }
133.
134. };
135. }
TreeViewAdapter.java是实现二级树形菜单的工具类,源码如下:
Java代码
1. package com.testExpandableList;
2.
3. import java.util.ArrayList;
4. import java.util.List;
5. import android.content.Context;
6. import android.util.Log;
7. import android.view.Gravity;
8. import android.view.View;
9. import android.view.ViewGroup;
10. import android.widget.AbsListView;
11. import android.widget.BaseExpandableListAdapter;
12. import android.widget.TextView;
13.
14.
15. public class TreeViewAdapter extends BaseExpandableListAdapter{
16. public static final int ItemHeight=48;//每项的高度
17. public static final int PaddingLeft=36;//每项的高度
18. private int myPaddingLeft=0;//如果是由SuperTreeView调用,则作为子项需要往右移
19.
20. static public class TreeNode{
21. Object parent;
22. new ArrayList();
23. }
24.
25. new ArrayList[tr]();
26. Context parentContext;
27.
28. public TreeViewAdapter(Context view,int myPaddingLeft)
29. {
30. parentContext=view;
31. this.myPaddingLeft=myPaddingLeft;
32. }
33.
34. public List[tr] GetTreeNode()
35. {
36. return treeNodes;
37. }
38.
39. public void UpdateTreeNode(List[tr] nodes)
40. {
41. treeNodes=nodes;
42. }
43.
44. public void RemoveAll()
45. {
46. treeNodes.clear();
47. }
48.
49. public Object getChild(int groupPosition, int childPosition) {
50. return treeNodes.get(groupPosition).childs.get(childPosition);
51. }
52.
53. public int getChildrenCount(int groupPosition) {
54. return treeNodes.get(groupPosition).childs.size();
55. }
56.
57. static public TextView getTextView(Context context) {
58. new AbsListView.LayoutParams(
59. ViewGroup.LayoutParams.FILL_PARENT, ItemHeight);
60.
61. new TextView(context);
62. textView.setLayoutParams(lp);
63. textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
64. return textView;
65. }
66.
67. public View getChildView(int groupPosition, int childPosition,
68. boolean isLastChild, View convertView, ViewGroup parent) {
69. this.parentContext);
70. textView.setText(getChild(groupPosition, childPosition).toString());
71. 0, 0, 0);
72. return textView;
73. }
74.
75. public View getGroupView(int groupPosition, boolean isExpanded,
76. View convertView, ViewGroup parent) {
77. this.parentContext);
78. textView.setText(getGroup(groupPosition).toString());
79. 1), 0, 0, 0);
80. return textView;
81. }
82.
83. public long getChildId(int groupPosition, int childPosition) {
84. return childPosition;
85. }
86.
87. public Object getGroup(int groupPosition) {
88. return treeNodes.get(groupPosition).parent;
89. }
90.
91. public int getGroupCount() {
92. return treeNodes.size();
93. }
94.
95. public long getGroupId(int groupPosition) {
96. return groupPosition;
97. }
98.
99. public boolean isChildSelectable(int groupPosition, int childPosition) {
100. return true;
101. }
102.
103. public boolean hasStableIds() {
104. return true;
105. }
106. }
SuperTreeViewAdapter.java是实现三级树形菜单的工具类,会用到TreeViewAdapter.java,源码如下:
Java代码
1. package com.testExpandableList;
2.
3. import java.util.ArrayList;
4. import java.util.List;
5. import com.testExpandableList.TreeViewAdapter.TreeNode;
6. import android.content.Context;
7. import android.view.View;
8. import android.view.ViewGroup;
9. import android.widget.AbsListView;
10. import android.widget.BaseExpandableListAdapter;
11. import android.widget.ExpandableListView;
12. import android.widget.ExpandableListView.OnChildClickListener;
13. import android.widget.ExpandableListView.OnGroupCollapseListener;
14. import android.widget.ExpandableListView.OnGroupExpandListener;
15. import android.widget.TextView;
16.
17. public class SuperTreeViewAdapter extends BaseExpandableListAdapter {
18.
19. static public class SuperTreeNode {
20. Object parent;
21. //二级树形菜单的结构体
22. new ArrayList[tr]();
23. }
24.
25. private List superTreeNodes = new ArrayList();
26. private Context parentContext;
27. private OnChildClickListener stvClickEvent;//外部回调函数
28.
29. public SuperTreeViewAdapter(Context view,OnChildClickListener stvClickEvent) {
30. parentContext = view;
31. this.stvClickEvent=stvClickEvent;
32. }
33.
34. public List GetTreeNode() {
35. return superTreeNodes;
36. }
37.
38. public void UpdateTreeNode(List node) {
39. superTreeNodes = node;
40. }
41.
42. public void RemoveAll()
43. {
44. superTreeNodes.clear();
45. }
46.
47. public Object getChild(int groupPosition, int childPosition) {
48. return superTreeNodes.get(groupPosition).childs.get(childPosition);
49. }
50.
51. public int getChildrenCount(int groupPosition) {
52. return superTreeNodes.get(groupPosition).childs.size();
53. }
54.
55. public ExpandableListView getExpandableListView() {
56. new AbsListView.LayoutParams(
57. ViewGroup.LayoutParams.FILL_PARENT, TreeViewAdapter.ItemHeight);
58. new ExpandableListView(parentContext);
59. superTreeView.setLayoutParams(lp);
60. return superTreeView;
61. }
62.
63. /**
64. * 三层树结构中的第二层是一个ExpandableListView
65. */
66. public View getChildView(int groupPosition, int childPosition,
67. boolean isLastChild, View convertView, ViewGroup parent) {
68. // 是
69. final ExpandableListView treeView = getExpandableListView();
70. final TreeViewAdapter treeViewAdapter = new TreeViewAdapter(this.parentContext,0);
71. //临时变量取得TreeViewAdapter的TreeNode集合,可为空
72. final TreeNode treeNode=(TreeNode) getChild(groupPosition, childPosition);
73. tmp.add(treeNode);
74. treeViewAdapter.UpdateTreeNode(tmp);
75. treeView.setAdapter(treeViewAdapter);
76.
77. //关键点:取得选中的二级树形菜单的父子节点,结果返回给外部回调函数
78. this.stvClickEvent);
79.
80. /**
81. * 关键点:第二级菜单展开时通过取得节点数来设置第三级菜单的大小
82. */
83. new OnGroupExpandListener() {
84. @Override
85. public void onGroupExpand(int groupPosition) {
86.
87. new AbsListView.LayoutParams(
88. ViewGroup.LayoutParams.FILL_PARENT,
89. 1)*TreeViewAdapter.ItemHeight + 10);
90. treeView.setLayoutParams(lp);
91. }
92. });
93.
94. /**
95. * 第二级菜单回收时设置为标准Item大小
96. */
97. new OnGroupCollapseListener() {
98. @Override
99. public void onGroupCollapse(int groupPosition) {
100.
101. new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
102. TreeViewAdapter.ItemHeight);
103. treeView.setLayoutParams(lp);
104. }
105. });
106. 0, 0, 0);
107. return treeView;
108. }
109.
110. /**
111. * 三级树结构中的首层是TextView,用于作为title
112. */
113. public View getGroupView(int groupPosition, boolean isExpanded,
114. View convertView, ViewGroup parent) {
115. this.parentContext);
116. textView.setText(getGroup(groupPosition).toString());
117. 0, 0, 0);
118. return textView;
119. }
120.
121. public long getChildId(int groupPosition, int childPosition) {
122. return childPosition;
123. }
124.
125. public Object getGroup(int groupPosition) {
126. return superTreeNodes.get(groupPosition).parent;
127. }
128.
129. public int getGroupCount() {
130. return superTreeNodes.size();
131. }
132.
133. public long getGroupId(int groupPosition) {
134. return groupPosition;
135. }
136.
137. public boolean isChildSelectable(int groupPosition, int childPosition) {
138. return true;
139. }
140.
141. public boolean hasStableIds() {
142. return true;
143. }
144. }
总结,使用ExpandableList实现三级树形菜单时有些bug不好解决,而且定义三维数组的时候也要倍加小心......所以尽量把数据化简来使用二级树形菜单。