zoukankan      html  css  js  c++  java
  • Android 多级树形菜单

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

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

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

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

     
    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源码如下:

    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是主类,调用其他工具类,源码如下:

     
    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是实现二级树形菜单的工具类,源码如下:

     
    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,源码如下:

     
    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.   
    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不好解决,而且定义三维数组的时候也要倍加小心......所以尽量把数据化简来使用二级树形菜单。

  • 相关阅读:
    springboot实现redis的分布式锁
    剑指offer--二维数组中查找
    剑指offer--二维数组中查找
    对JDK动态代理的模拟实现
    Spring(4)AOP
    设计模式之单例模式(Java)
    【Java并发系列】--Java内存模型
    maven 解决jar包冲突及简单使用
    基于注解的SpringAOP源码解析(三)
    Java代码中可以优化性能的小细节
  • 原文地址:https://www.cnblogs.com/xiaochao1234/p/3990313.html
Copyright © 2011-2022 走看看