Android提高十七篇之多级树形菜单的实现

系统 1827 0

在 Android里要实现树形菜单,都是用ExpandableList(也有高手自己继承ListView或者LinearLayout来做),但是 ExpandableList一般只能实现2级树形菜单......本文也依然使用ExpandableList,但是要实现的是3级树形菜单。 本文程序运行效果图:

当 用BaseExpandableListAdapter来实现二级树形菜单时,父项(getGroupView())和子项 (getChildView())都是使用TextView。当要实现三级树形菜单时,子项(getChildView())就必须使用 ExpandableList了.......另外还要定义结构体来方便调用三级树形的数据, 二级树形菜单可以用如下:

view plaincopy to clipboardprint?
  1. static   public   class  TreeNode{  
  2.     Object parent;  
  3.     List<Object> childs= new  ArrayList<Object>();  
  4. }  

三级树形菜单可以用如下,子项是二级树形菜单的结构体:

view plaincopy to clipboardprint?
  1. static   public   class  SuperTreeNode {  
  2.     Object parent;  
  3.      //二级树形菜单的结构体   
  4.     List<TreeViewAdapter.TreeNode> childs =  new  ArrayList<TreeViewAdapter.TreeNode>();  
  5. }  

实现三级树形菜单有两点要注意的:

1、第二级也是个树形菜单,因此必须在第二级项目展开/回收时设置足够的空间来完全显示二级树形菜单;

2、在实现三级树形菜单时,发现菜单的方法都是用不了(如OnChildClickListener、OnGroupClickListener等),因此要获得选中的数据就必须在外部定义好回调函数,然后在第二级生成二级树形菜单时回调这个外部函数。

PS:本文在解决No.2关键点的时候,只能取得第三级选中的序号.....而第一,第二级依然无法获取其序号。

main.xml源码如下:

view plaincopy to clipboardprint?
  1. <? xml   version = "1.0"   encoding = "utf-8" ?>   
  2. < LinearLayout   xmlns:android = "http://schemas.android.com/apk/res/android"   
  3.      android:orientation = "vertical"   android:layout_width = "fill_parent"   
  4.      android:layout_height = "fill_parent" >   
  5.      < LinearLayout   android:id = "@+id/LinearLayout01"   
  6.          android:layout_width = "wrap_content"   android:layout_height = "wrap_content" >   
  7.          < Button   android:layout_height = "wrap_content"   android:text = "两层结构"   
  8.              android:layout_width = "160dip"   android:id = "@+id/btnNormal" > </ Button >   
  9.          < Button   android:layout_height = "wrap_content"   android:text = "三层结构"   
  10.              android:layout_width = "160dip"   android:id = "@+id/btnSuper" > </ Button >   
  11.      </ LinearLayout >   
  12.      < ExpandableListView   android:id = "@+id/ExpandableListView01"   
  13.          android:layout_width = "fill_parent"   android:layout_height = "fill_parent" > </ ExpandableListView >   
  14. </ LinearLayout >   

testExpandableList.java是主类,调用其他工具类,源码如下:

view plaincopy to clipboardprint?
  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.         btnNormal=(Button) this .findViewById(R.id.btnNormal);  
  46.         btnNormal.setOnClickListener( new  ClickEvent());  
  47.         btnSuper=(Button) this .findViewById(R.id.btnSuper);  
  48.         btnSuper.setOnClickListener( new  ClickEvent());  
  49.         adapter= new  TreeViewAdapter( this ,TreeViewAdapter.PaddingLeft>> 1 );  
  50.         superAdapter= new  SuperTreeViewAdapter( this ,stvClickEvent);  
  51.         expandableList=(ExpandableListView) testExpandableList. 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<TreeViewAdapter.TreeNode> treeNode = adapter.GetTreeNode();  
  66.                  for ( int  i= 0 ;i<groups.length;i++)  
  67.                 {  
  68.                     TreeViewAdapter.TreeNode node= 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.                 expandableList.setOnChildClickListener( new  OnChildClickListener(){  
  80.   
  81.                      @Override   
  82.                      public   boolean  onChildClick(ExpandableListView arg0, View arg1,  
  83.                              int  parent,  int  children,  long  arg4) {  
  84.                           
  85.                         String str= "parent id:" +String.valueOf(parent)+ ",children id:" +String.valueOf(children);  
  86.                         Toast.makeText(testExpandableList. this , str,  300 ).show();  
  87.                          return   false ;  
  88.                     }  
  89.                 });  
  90.             }  
  91.              else   if (v==btnSuper){  
  92.                 List<SuperTreeViewAdapter.SuperTreeNode> superTreeNode = superAdapter.GetTreeNode();  
  93.                  for ( int  i= 0 ;i<parent.length;i++) //第一层   
  94.                 {  
  95.                     SuperTreeViewAdapter.SuperTreeNode superNode= new  SuperTreeViewAdapter.SuperTreeNode();  
  96.                     superNode.parent=parent[i];  
  97.                       
  98.                      //第二层   
  99.                      for ( int  ii= 0 ;ii<child_grandson.length;ii++)  
  100.                     {  
  101.                         TreeViewAdapter.TreeNode node= new  TreeViewAdapter.TreeNode();  
  102.                         node.parent=child_grandson[ii][ 0 ][ 0 ]; //第二级菜单的标题   
  103.                           
  104.                          for ( int  iii= 0 ;iii<child_grandson[ii][ 1 ].length;iii++) //第三级菜单   
  105.                         {  
  106.                             node.childs.add(child_grandson[ii][ 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.     OnChildClickListener stvClickEvent= new  OnChildClickListener(){  
  123.   
  124.          @Override   
  125.          public   boolean  onChildClick(ExpandableListView parent,  
  126.                 View v,  int  groupPosition,  int  childPosition,  
  127.                  long  id) {  
  128.             String str= "parent id:" +String.valueOf(groupPosition)+ ",children id:" +String.valueOf(childPosition);  
  129.             Toast.makeText(testExpandableList. this , str,  300 ).show();  
  130.               
  131.              return   false ;  
  132.         }  
  133.           
  134.     };  
  135. }  

TreeViewAdapter.java是实现二级树形菜单的工具类,源码如下:

view plaincopy to clipboardprint?
  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.         List<Object> childs= new  ArrayList<Object>();  
  23.     }  
  24.       
  25.     List<TreeNode> treeNodes =  new  ArrayList<TreeNode>();  
  26.     Context parentContext;  
  27.       
  28.      public  TreeViewAdapter(Context view, int  myPaddingLeft)  
  29.     {  
  30.         parentContext=view;  
  31.          this .myPaddingLeft=myPaddingLeft;  
  32.     }  
  33.       
  34.      public  List<TreeNode> GetTreeNode()  
  35.     {  
  36.          return  treeNodes;  
  37.     }  
  38.       
  39.      public   void  UpdateTreeNode(List<TreeNode> 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.         AbsListView.LayoutParams lp =  new  AbsListView.LayoutParams(  
  59.                 ViewGroup.LayoutParams.FILL_PARENT, ItemHeight);  
  60.   
  61.         TextView textView =  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.         TextView textView = getTextView( this .parentContext);  
  70.         textView.setText(getChild(groupPosition, childPosition).toString());  
  71.         textView.setPadding(myPaddingLeft+PaddingLeft,  0 0 0 );  
  72.          return  textView;  
  73.     }  
  74.   
  75.      public  View getGroupView( int  groupPosition,  boolean  isExpanded,  
  76.             View convertView, ViewGroup parent) {  
  77.         TextView textView = getTextView( this .parentContext);  
  78.         textView.setText(getGroup(groupPosition).toString());  
  79.         textView.setPadding(myPaddingLeft+(PaddingLeft>> 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 ,源码如下:

view plaincopy to clipboardprint?
  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.         List<TreeViewAdapter.TreeNode> childs =  new  ArrayList<TreeViewAdapter.TreeNode>();  
  23.     }  
  24.   
  25.      private  List<SuperTreeNode> superTreeNodes =  new  ArrayList<SuperTreeNode>();  
  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<SuperTreeNode> GetTreeNode() {  
  35.          return  superTreeNodes;  
  36.     }  
  37.   
  38.      public   void  UpdateTreeNode(List<SuperTreeNode> 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.         AbsListView.LayoutParams lp =  new  AbsListView.LayoutParams(  
  57.                 ViewGroup.LayoutParams.FILL_PARENT, TreeViewAdapter.ItemHeight);  
  58.         ExpandableListView superTreeView =  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.         List<TreeNode> tmp = treeViewAdapter.GetTreeNode(); //临时变量取得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.         treeView.setOnChildClickListener( this .stvClickEvent);  
  79.           
  80.          /**  
  81.          * 关键点:第二级菜单展开时通过取得节点数来设置第三级菜单的大小  
  82.          */   
  83.         treeView.setOnGroupExpandListener( new  OnGroupExpandListener() {  
  84.              @Override   
  85.              public   void  onGroupExpand( int  groupPosition) {  
  86.                   
  87.                 AbsListView.LayoutParams lp =  new  AbsListView.LayoutParams(  
  88.                         ViewGroup.LayoutParams.FILL_PARENT,  
  89.                         (treeNode.childs.size()+ 1 )*TreeViewAdapter.ItemHeight +  10 );  
  90.                 treeView.setLayoutParams(lp);  
  91.             }  
  92.         });  
  93.           
  94.          /**  
  95.          * 第二级菜单回收时设置为标准Item大小  
  96.          */   
  97.         treeView.setOnGroupCollapseListener( new  OnGroupCollapseListener() {  
  98.              @Override   
  99.              public   void  onGroupCollapse( int  groupPosition) {  
  100.                   
  101.                 AbsListView.LayoutParams lp =  new  AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,  
  102.                         TreeViewAdapter.ItemHeight);  
  103.                 treeView.setLayoutParams(lp);  
  104.             }  
  105.         });  
  106.         treeView.setPadding(TreeViewAdapter.PaddingLeft,  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.         TextView textView = TreeViewAdapter.getTextView( this .parentContext);  
  116.         textView.setText(getGroup(groupPosition).toString());  
  117.         textView.setPadding(TreeViewAdapter.PaddingLeft,  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.   
0
0
分享到:
评论

Android提高十七篇之多级树形菜单的实现


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论