本文来自http://blog.csdn.net/hellogv/,引用必须注明出处!
在Android里要实现树形菜单,都是用ExpandableList(也有高手自己继承ListView或者LinearLayout来做),但是ExpandableList一般只能实现2级树形菜单......本文也依然使用ExpandableList,但是要实现的是3级树形菜单。本文程序运行效果图:
当用BaseExpandableListAdapter来实现二级树形菜单时,父项(getGroupView())和子项(getChildView())都是使用TextView。当要实现三级树形菜单时,子项(getChildView())就必须使用ExpandableList了.......另外还要定义结构体来方便调用三级树形的数据,二级树形菜单可以用如下:
- staticpublicclassTreeNode{
- Objectparent;
- List<Object>childs=newArrayList<Object>();
- }
三级树形菜单可以用如下,子项是二级树形菜单的结构体:
- staticpublicclassSuperTreeNode{
- Objectparent;
-
- List<TreeViewAdapter.TreeNode>childs=newArrayList<TreeViewAdapter.TreeNode>();
- }
实现三级树形菜单有两点要注意的:
1、第二级也是个树形菜单,因此必须在第二级项目展开/回收时设置足够的空间来完全显示二级树形菜单;
2、在实现三级树形菜单时,发现菜单的方法都是用不了(如OnChildClickListener、OnGroupClickListener等),因此要获得选中的数据就必须在外部定义好回调函数,然后在第二级生成二级树形菜单时回调这个外部函数。
PS:本文在解决No.2关键点的时候,只能取得第三级选中的序号.....而第一,第二级依然无法获取其序号。
main.xml源码如下:
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <LinearLayoutandroid:id="@+id/LinearLayout01"
- android:layout_width="wrap_content"android:layout_height="wrap_content">
- <Buttonandroid:layout_height="wrap_content"android:text="两层结构"
- android:layout_width="160dip"android:id="@+id/btnNormal"></Button>
- <Buttonandroid:layout_height="wrap_content"android:text="三层结构"
- android:layout_width="160dip"android:id="@+id/btnSuper"></Button>
- </LinearLayout>
- <ExpandableListViewandroid:id="@+id/ExpandableListView01"
- android:layout_width="fill_parent"android:layout_height="fill_parent"></ExpandableListView>
- </LinearLayout>
testExpandableList.java是主类,调用其他工具类,源码如下:
- packagecom.testExpandableList;
-
-
- importjava.util.List;
- importandroid.app.Activity;
- importandroid.os.Bundle;
- importandroid.util.Log;
- importandroid.view.View;
- importandroid.widget.Button;
- importandroid.widget.ExpandableListView;
- importandroid.widget.ExpandableListView.OnChildClickListener;
- importandroid.widget.Toast;
-
- publicclasstestExpandableListextendsActivity{
-
- ExpandableListViewexpandableList;
- TreeViewAdapteradapter;
- SuperTreeViewAdaptersuperAdapter;
- ButtonbtnNormal,btnSuper;
-
- publicString[]groups={"xxxx好友","xxxx同学","xxxxx女人"};
- publicString[][]child={
- {"A君","B君","C君","D君"},
- {"同学甲","同学乙","同学丙"},
- {"御姐","萝莉"}
- };
-
- publicString[]parent={"xxxx好友","xxxx同学"};
- publicString[][][]child_grandson={
- {{"A君"},
- {"AA","AAA"}},
- {{"B君"},
- {"BBB","BBBB","BBBBB"}},
- {{"C君"},
- {"CCC","CCCC"}},
- {{"D君"},
- {"DDD","DDDD","DDDDD"}},
- };
-
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- this.setTitle("ExpandableListView练习----hellogv");
- btnNormal=(Button)this.findViewById(R.id.btnNormal);
- btnNormal.setOnClickListener(newClickEvent());
- btnSuper=(Button)this.findViewById(R.id.btnSuper);
- btnSuper.setOnClickListener(newClickEvent());
- adapter=newTreeViewAdapter(this,TreeViewAdapter.PaddingLeft>>1);
- superAdapter=newSuperTreeViewAdapter(this,stvClickEvent);
- expandableList=(ExpandableListView)testExpandableList.this.findViewById(R.id.ExpandableListView01);
- }
-
- classClickEventimplementsView.OnClickListener{
-
- @Override
- publicvoidonClick(Viewv){
- adapter.RemoveAll();
- adapter.notifyDataSetChanged();
- superAdapter.RemoveAll();
- superAdapter.notifyDataSetChanged();
-
- if(v==btnNormal)
- {
- List<TreeViewAdapter.TreeNode>treeNode=adapter.GetTreeNode();
- for(inti=0;i<groups.length;i++)
- {
- TreeViewAdapter.TreeNodenode=newTreeViewAdapter.TreeNode();
- node.parent=groups[i];
- for(intii=0;ii<child[i].length;ii++)
- {
- node.childs.add(child[i][ii]);
- }
- treeNode.add(node);
- }
-
- adapter.UpdateTreeNode(treeNode);
- expandableList.setAdapter(adapter);
- expandableList.setOnChildClickListener(newOnChildClickListener(){
-
- @Override
- publicbooleanonChildClick(ExpandableListViewarg0,Viewarg1,
- intparent,intchildren,longarg4){
-
- Stringstr="parentid:"+String.valueOf(parent)+",childrenid:"+String.valueOf(children);
- Toast.makeText(testExpandableList.this,str,300).show();
- returnfalse;
- }
- });
- }
- elseif(v==btnSuper){
- List<SuperTreeViewAdapter.SuperTreeNode>superTreeNode=superAdapter.GetTreeNode();
- for(inti=0;i<parent.length;i++)
- {
- SuperTreeViewAdapter.SuperTreeNodesuperNode=newSuperTreeViewAdapter.SuperTreeNode();
- superNode.parent=parent[i];
-
-
- for(intii=0;ii<child_grandson.length;ii++)
- {
- TreeViewAdapter.TreeNodenode=newTreeViewAdapter.TreeNode();
- node.parent=child_grandson[ii][0][0];
-
- for(intiii=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);
- }
- }
- }
-
-
-
-
- OnChildClickListenerstvClickEvent=newOnChildClickListener(){
-
- @Override
- publicbooleanonChildClick(ExpandableListViewparent,
- Viewv,intgroupPosition,intchildPosition,
- longid){
- Stringstr="parentid:"+String.valueOf(groupPosition)+",childrenid:"+String.valueOf(childPosition);
- Toast.makeText(testExpandableList.this,str,300).show();
-
- returnfalse;
- }
-
- };
- }
TreeViewAdapter.java是实现二级树形菜单的工具类,源码如下:
- packagecom.testExpandableList;
-
- importjava.util.ArrayList;
- importjava.util.List;
- importandroid.content.Context;
- importandroid.util.Log;
- importandroid.view.Gravity;
- importandroid.view.View;
- importandroid.view.ViewGroup;
- importandroid.widget.AbsListView;
- importandroid.widget.BaseExpandableListAdapter;
- importandroid.widget.TextView;
-
-
- publicclassTreeViewAdapterextendsBaseExpandableListAdapter{
- publicstaticfinalintItemHeight=48;
- publicstaticfinalintPaddingLeft=36;
- privateintmyPaddingLeft=0;
-
- staticpublicclassTreeNode{
- Objectparent;
- List<Object>childs=newArrayList<Object>();
- }
-
- List<TreeNode>treeNodes=newArrayList<TreeNode>();
- ContextparentContext;
-
- publicTreeViewAdapter(Contextview,intmyPaddingLeft)
- {
- parentContext=view;
- this.myPaddingLeft=myPaddingLeft;
- }
-
- publicList<TreeNode>GetTreeNode()
- {
- returntreeNodes;
- }
-
- publicvoidUpdateTreeNode(List<TreeNode>nodes)
- {
- treeNodes=nodes;
- }
-
- publicvoidRemoveAll()
- {
- treeNodes.clear();
- }
-
- publicObjectgetChild(intgroupPosition,intchildPosition){
- returntreeNodes.get(groupPosition).childs.get(childPosition);
- }
-
- publicintgetChildrenCount(intgroupPosition){
- returntreeNodes.get(groupPosition).childs.size();
- }
-
- staticpublicTextViewgetTextView(Contextcontext){
- AbsListView.LayoutParamslp=newAbsListView.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,ItemHeight);
-
- TextViewtextView=newTextView(context);
- textView.setLayoutParams(lp);
- textView.setGravity(Gravity.CENTER_VERTICAL|Gravity.LEFT);
- returntextView;
- }
-
- publicViewgetChildView(intgroupPosition,intchildPosition,
- booleanisLastChild,ViewconvertView,ViewGroupparent){
- TextViewtextView=getTextView(this.parentContext);
- textView.setText(getChild(groupPosition,childPosition).toString());
- textView.setPadding(myPaddingLeft+PaddingLeft,0,0,0);
- returntextView;
- }
-
- publicViewgetGroupView(intgroupPosition,booleanisExpanded,
- ViewconvertView,ViewGroupparent){
- TextViewtextView=getTextView(this.parentContext);
- textView.setText(getGroup(groupPosition).toString());
- textView.setPadding(myPaddingLeft+(PaddingLeft>>1),0,0,0);
- returntextView;
- }
-
- publiclonggetChildId(intgroupPosition,intchildPosition){
- returnchildPosition;
- }
-
- publicObjectgetGroup(intgroupPosition){
- returntreeNodes.get(groupPosition).parent;
- }
-
- publicintgetGroupCount(){
- returntreeNodes.size();
- }
-
- publiclonggetGroupId(intgroupPosition){
- returngroupPosition;
- }
-
- publicbooleanisChildSelectable(intgroupPosition,intchildPosition){
- returntrue;
- }
-
- publicbooleanhasStableIds(){
- returntrue;
- }
- }
SuperTreeViewAdapter.java是实现三级树形菜单的工具类,会用到TreeViewAdapter.java,源码如下:
- packagecom.testExpandableList;
-
- importjava.util.ArrayList;
- importjava.util.List;
- importcom.testExpandableList.TreeViewAdapter.TreeNode;
- importandroid.content.Context;
- importandroid.view.View;
- importandroid.view.ViewGroup;
- importandroid.widget.AbsListView;
- importandroid.widget.BaseExpandableListAdapter;
- importandroid.widget.ExpandableListView;
- importandroid.widget.ExpandableListView.OnChildClickListener;
- importandroid.widget.ExpandableListView.OnGroupCollapseListener;
- importandroid.widget.ExpandableListView.OnGroupExpandListener;
- importandroid.widget.TextView;
-
- publicclassSuperTreeViewAdapterextendsBaseExpandableListAdapter{
-
- staticpublicclassSuperTreeNode{
- Objectparent;
-
- List<TreeViewAdapter.TreeNode>childs=newArrayList<TreeViewAdapter.TreeNode>();
- }
-
- privateList<SuperTreeNode>superTreeNodes=newArrayList<SuperTreeNode>();
- privateContextparentContext;
- privateOnChildClickListenerstvClickEvent;
-
- publicSuperTreeViewAdapter(Contextview,OnChildClickListenerstvClickEvent){
- parentContext=view;
- this.stvClickEvent=stvClickEvent;
- }
-
- publicList<SuperTreeNode>GetTreeNode(){
- returnsuperTreeNodes;
- }
-
- publicvoidUpdateTreeNode(List<SuperTreeNode>node){
- superTreeNodes=node;
- }
-
- publicvoidRemoveAll()
- {
- superTreeNodes.clear();
- }
-
- publicObjectgetChild(intgroupPosition,intchildPosition){
- returnsuperTreeNodes.get(groupPosition).childs.get(childPosition);
- }
-
- publicintgetChildrenCount(intgroupPosition){
- returnsuperTreeNodes.get(groupPosition).childs.size();
- }
-
- publicExpandableListViewgetExpandableListView(){
- AbsListView.LayoutParamslp=newAbsListView.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,TreeViewAdapter.ItemHeight);
- ExpandableListViewsuperTreeView=newExpandableListView(parentContext);
- superTreeView.setLayoutParams(lp);
- returnsuperTreeView;
- }
-
-
-
-
- publicViewgetChildView(intgroupPosition,intchildPosition,
- booleanisLastChild,ViewconvertView,ViewGroupparent){
-
- finalExpandableListViewtreeView=getExpandableListView();
- finalTreeViewAdaptertreeViewAdapter=newTreeViewAdapter(this.parentContext,0);
- List<TreeNode>tmp=treeViewAdapter.GetTreeNode();
- finalTreeNodetreeNode=(TreeNode)getChild(groupPosition,childPosition);
- tmp.add(treeNode);
- treeViewAdapter.UpdateTreeNode(tmp);
- treeView.setAdapter(treeViewAdapter);
-
-
- treeView.setOnChildClickListener(this.stvClickEvent);
-
-
-
-
- treeView.setOnGroupExpandListener(newOnGroupExpandListener(){
- @Override
- publicvoidonGroupExpand(intgroupPosition){
-
- AbsListView.LayoutParamslp=newAbsListView.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- (treeNode.childs.size()+1)*TreeViewAdapter.ItemHeight+10);
- treeView.setLayoutParams(lp);
- }
- });
-
-
-
-
- treeView.setOnGroupCollapseListener(newOnGroupCollapseListener(){
- @Override
- publicvoidonGroupCollapse(intgroupPosition){
-
- AbsListView.LayoutParamslp=newAbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
- TreeViewAdapter.ItemHeight);
- treeView.setLayoutParams(lp);
- }
- });
- treeView.setPadding(TreeViewAdapter.PaddingLeft,0,0,0);
- returntreeView;
- }
-
-
-
-
- publicViewgetGroupView(intgroupPosition,booleanisExpanded,
- ViewconvertView,ViewGroupparent){
- TextViewtextView=TreeViewAdapter.getTextView(this.parentContext);
- textView.setText(getGroup(groupPosition).toString());
- textView.setPadding(TreeViewAdapter.PaddingLeft,0,0,0);
- returntextView;
- }
-
- publiclonggetChildId(intgroupPosition,intchildPosition){
- returnchildPosition;
- }
-
- publicObjectgetGroup(intgroupPosition){
- returnsuperTreeNodes.get(groupPosition).parent;
- }
-
- publicintgetGroupCount(){
- returnsuperTreeNodes.size();
- }
-
- publiclonggetGroupId(intgroupPosition){
- returngroupPosition;
- }
-
- publicbooleanisChildSelectable(intgroupPosition,intchildPosition){
- returntrue;
- }
-
- publicbooleanhasStableIds(){
- returntrue;
- }
- }
总结,使用ExpandableList实现三级树形菜单时有些bug不好解决,而且定义三维数组的时候也要倍加小心......所以尽量把数据化简来使用二级树形菜单。