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

来源:互联网 发布:股票的数据挖掘 编辑:程序博客网 时间:2024/05/16 01:11

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

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


  1. static public class TreeNode{
  2.                 Object parent;
  3.                 List childs=new ArrayList();
  4.         }
复制代码
三级树形菜单可以用如下,子项是二级树形菜单的结构体:

  1. static public class SuperTreeNode {
  2.                 Object parent;
  3.                 //二级树形菜单的结构体
  4.                 List[tr] childs = new ArrayList[tr]();
  5.         }
复制代码
实现三级树形菜单有两点要注意的:1、第二级也是个树形菜单,因此必须在第二级项目展开/回收时设置足够的空间来完全显示二级树形菜单;2、在实现三级树形菜单时,发现菜单的方法都是用不了(如OnChildClickListener、OnGroupClickListener等),因此要获得选中的数据就必须在外部定义好回调函数,然后在第二级生成二级树形菜单时回调这个外部函数。PS:本文在解决No.2关键点的时候,只能取得第三级选中的序号.....而第一,第二级依然无法获取其序号。main.xml源码如下:

  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是主类,调用其他工具类,源码如下:
  1. package com.testExpandableList;


  2. import java.util.List;
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.util.Log;
  6. import android.view.View;
  7. import android.widget.Button;
  8. import android.widget.ExpandableListView;
  9. import android.widget.ExpandableListView.OnChildClickListener;
  10. import android.widget.Toast;

  11. public class testExpandableList extends Activity {
  12.     /** Called when the activity is first created. */
  13.         ExpandableListView expandableList;
  14.         TreeViewAdapter adapter;
  15.         SuperTreeViewAdapter superAdapter;
  16.         Button btnNormal,btnSuper;
  17.     // Sample data set.  children[i] contains the children (String[]) for groups[i].
  18.     public String[] groups = { "xxxx好友", "xxxx同学", "xxxxx女人"};
  19.     public String[][]  child= {
  20.             { "A君", "B君", "C君", "D君" },
  21.             { "同学甲", "同学乙", "同学丙"},
  22.             { "御姐", "萝莉" }
  23.     };
  24.     
  25.     public String[] parent = { "xxxx好友", "xxxx同学"};
  26.     public String[][][]  child_grandson= {
  27.                     {{"A君"},
  28.                             {"AA","AAA"}},
  29.                     {{"B君"},
  30.                             {"BBB","BBBB","BBBBB"}},
  31.                     {{"C君"},
  32.                             {"CCC","CCCC"}},
  33.                     {{"D君"},
  34.                             {"DDD","DDDD","DDDDD"}},
  35.     };
  36.     
  37.     @Override
  38.     public void onCreate(Bundle savedInstanceState) {
  39.         super.onCreate(savedInstanceState);
  40.         setContentView(R.layout.main);
  41.         this.setTitle("ExpandableListView练习----hellogv");
  42.         btnNormal=(Button)this.findViewById(R.id.btnNormal);
  43.         btnNormal.setOnClickListener(new ClickEvent());
  44.         btnSuper=(Button)this.findViewById(R.id.btnSuper);
  45.         btnSuper.setOnClickListener(new ClickEvent());
  46.         adapter=new TreeViewAdapter(this,TreeViewAdapter.PaddingLeft>>1);
  47.         superAdapter=new SuperTreeViewAdapter(this,stvClickEvent);
  48.         expandableList=(ExpandableListView) testExpandableList.this.findViewById(R.id.ExpandableListView01);
  49.     }
  50.     
  51.     class ClickEvent implements View.OnClickListener{

  52.                 @Override
  53.                 public void onClick(View v) {
  54.                         adapter.RemoveAll();
  55.                         adapter.notifyDataSetChanged();
  56.                         superAdapter.RemoveAll();
  57.                         superAdapter.notifyDataSetChanged();
  58.                         
  59.                         if(v==btnNormal)
  60.                         {
  61.                         List[tr] treeNode = adapter.GetTreeNode();
  62.                         for(int i=0;i<groups.length;i++)
  63.                         {
  64.                                 TreeViewAdapter.TreeNode node=new TreeViewAdapter.TreeNode();
  65.                                 node.parent=groups[i];
  66.                                 for(int ii=0;ii<child[i].length;ii++)
  67.                                 {
  68.                                         node.childs.add(child[i][ii]);
  69.                                 }
  70.                                 treeNode.add(node);
  71.                         }
  72.                         
  73.                         adapter.UpdateTreeNode(treeNode);     
  74.                         expandableList.setAdapter(adapter);
  75.                         expandableList.setOnChildClickListener(new OnChildClickListener(){

  76.                                         @Override
  77.                                         public boolean onChildClick(ExpandableListView arg0, View arg1,
  78.                                                         int parent, int children, long arg4) {
  79.                                                 
  80.                                                 String str="parent id:"+String.valueOf(parent)+",children id:"+String.valueOf(children);
  81.                                                 Toast.makeText(testExpandableList.this, str, 300).show();
  82.                                                 return false;
  83.                                         }
  84.                         });
  85.                         }
  86.                         else if(v==btnSuper){
  87.                                 List superTreeNode = superAdapter.GetTreeNode();
  88.                         for(int i=0;i<parent.length;i++) 第一层
  89.                         {
  90.                                 SuperTreeViewAdapter.SuperTreeNode superNode=new SuperTreeViewAdapter.SuperTreeNode();
  91.                                 superNode.parent=parent[i];
  92.                                 
  93.                                 //第二层
  94.                                 for(int ii=0;ii<child_grandson.length;ii++)
  95.                             {
  96.                                     TreeViewAdapter.TreeNode node=new TreeViewAdapter.TreeNode();
  97.                                     node.parent=child_grandson[ii][0][0];//第二级菜单的标题
  98.                                     
  99.                                     for(int iii=0;iii<child_grandson[ii][1].length;iii++) 第三级菜单
  100.                                     {
  101.                                             node.childs.add(child_grandson[ii][1][iii]);
  102.                                     }
  103.                                     superNode.childs.add(node);
  104.                             }
  105.                                 superTreeNode.add(superNode);
  106.                                 
  107.                         }
  108.                         superAdapter.UpdateTreeNode(superTreeNode);
  109.                         expandableList.setAdapter(superAdapter);
  110.                         }
  111.                 }
  112.     }

  113.     /**
  114.      * 三级树形菜单的事件不再可用,本函数由三级树形菜单的子项(二级菜单)进行回调
  115.      */
  116.     OnChildClickListener stvClickEvent=new OnChildClickListener(){

  117.                 @Override
  118.                 public boolean onChildClick(ExpandableListView parent,
  119.                                 View v, int groupPosition, int childPosition,
  120.                                 long id) {
  121.                         String str="parent id:"+String.valueOf(groupPosition)+",children id:"+String.valueOf(childPosition);
  122.                         Toast.makeText(testExpandableList.this, str, 300).show();
  123.                         
  124.                         return false;
  125.                 }
  126.             
  127.     };
  128. }
复制代码
TreeViewAdapter.java是实现二级树形菜单的工具类,源码如下:
  1. package com.testExpandableList;

  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import android.content.Context;
  5. import android.util.Log;
  6. import android.view.Gravity;
  7. import android.view.View;
  8. import android.view.ViewGroup;
  9. import android.widget.AbsListView;
  10. import android.widget.BaseExpandableListAdapter;
  11. import android.widget.TextView;


  12. public class TreeViewAdapter extends BaseExpandableListAdapter{
  13.         public static final int ItemHeight=48;//每项的高度
  14.         public static final int PaddingLeft=36;//每项的高度
  15.         private int myPaddingLeft=0;//如果是由SuperTreeView调用,则作为子项需要往右移

  16.         static public class TreeNode{
  17.                 Object parent;
  18.                 List childs=new ArrayList();
  19.         }
  20.         
  21.         List[tr] treeNodes = new ArrayList[tr]();
  22.         Context parentContext;
  23.         
  24.         public TreeViewAdapter(Context view,int myPaddingLeft)
  25.         {
  26.                 parentContext=view;
  27.                 this.myPaddingLeft=myPaddingLeft;
  28.         }
  29.         
  30.         public List[tr] GetTreeNode()
  31.         {
  32.                 return treeNodes;
  33.         }
  34.         
  35.         public void UpdateTreeNode(List[tr] nodes)
  36.         {
  37.                 treeNodes=nodes;
  38.         }
  39.         
  40.         public void RemoveAll()
  41.         {
  42.                 treeNodes.clear();
  43.         }
  44.         
  45.         public Object getChild(int groupPosition, int childPosition) {
  46.                 return treeNodes.get(groupPosition).childs.get(childPosition);
  47.         }

  48.         public int getChildrenCount(int groupPosition) {
  49.                 return treeNodes.get(groupPosition).childs.size();
  50.         }

  51.         static public TextView getTextView(Context context) {
  52.                 AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
  53.                                 ViewGroup.LayoutParams.FILL_PARENT, ItemHeight);

  54.                 TextView textView = new TextView(context);
  55.                 textView.setLayoutParams(lp);
  56.                 textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
  57.                 return textView;
  58.         }

  59.         public View getChildView(int groupPosition, int childPosition,
  60.                         boolean isLastChild, View convertView, ViewGroup parent) {
  61.                 TextView textView = getTextView(this.parentContext);
  62.                 textView.setText(getChild(groupPosition, childPosition).toString());
  63.                 textView.setPadding(myPaddingLeft+PaddingLeft, 0, 0, 0);
  64.                 return textView;
  65.         }

  66.         public View getGroupView(int groupPosition, boolean isExpanded,
  67.                         View convertView, ViewGroup parent) {
  68.                 TextView textView = getTextView(this.parentContext);
  69.                 textView.setText(getGroup(groupPosition).toString());
  70.                 textView.setPadding(myPaddingLeft+(PaddingLeft>>1), 0, 0, 0);
  71.                 return textView;
  72.         }

  73.         public long getChildId(int groupPosition, int childPosition) {
  74.                 return childPosition;
  75.         }

  76.         public Object getGroup(int groupPosition) {
  77.                 return treeNodes.get(groupPosition).parent;
  78.         }

  79.         public int getGroupCount() {
  80.                 return treeNodes.size();
  81.         }

  82.         public long getGroupId(int groupPosition) {
  83.                 return groupPosition;
  84.         }

  85.         public boolean isChildSelectable(int groupPosition, int childPosition) {
  86.                 return true;
  87.         }

  88.         public boolean hasStableIds() {
  89.                 return true;
  90.         }
  91. }
复制代码
SuperTreeViewAdapter.java是实现三级树形菜单的工具类,会用到TreeViewAdapter.java,源码如下:
  1. package com.testExpandableList;

  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import com.testExpandableList.TreeViewAdapter.TreeNode;
  5. import android.content.Context;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8. import android.widget.AbsListView;
  9. import android.widget.BaseExpandableListAdapter;
  10. import android.widget.ExpandableListView;
  11. import android.widget.ExpandableListView.OnChildClickListener;
  12. import android.widget.ExpandableListView.OnGroupCollapseListener;
  13. import android.widget.ExpandableListView.OnGroupExpandListener;
  14. import android.widget.TextView;

  15. public class SuperTreeViewAdapter extends BaseExpandableListAdapter {

  16.         static public class SuperTreeNode {
  17.                 Object parent;
  18.                 //二级树形菜单的结构体
  19.                 List[tr] childs = new ArrayList[tr]();
  20.         }

  21.         private List superTreeNodes = new ArrayList();
  22.         private Context parentContext;
  23.         private OnChildClickListener stvClickEvent;//外部回调函数
  24.         
  25.         public SuperTreeViewAdapter(Context view,OnChildClickListener stvClickEvent) {
  26.                 parentContext = view;
  27.                 this.stvClickEvent=stvClickEvent;
  28.         }

  29.         public List GetTreeNode() {
  30.                 return superTreeNodes;
  31.         }

  32.         public void UpdateTreeNode(List node) {
  33.                 superTreeNodes = node;
  34.         }
  35.         
  36.         public void RemoveAll()
  37.         {
  38.                 superTreeNodes.clear();
  39.         }
  40.         
  41.         public Object getChild(int groupPosition, int childPosition) {
  42.                 return superTreeNodes.get(groupPosition).childs.get(childPosition);
  43.         }

  44.         public int getChildrenCount(int groupPosition) {
  45.                 return superTreeNodes.get(groupPosition).childs.size();
  46.         }

  47.         public ExpandableListView getExpandableListView() {
  48.                 AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
  49.                                 ViewGroup.LayoutParams.FILL_PARENT, TreeViewAdapter.ItemHeight);
  50.                 ExpandableListView superTreeView = new ExpandableListView(parentContext);
  51.                 superTreeView.setLayoutParams(lp);
  52.                 return superTreeView;
  53.         }

  54.         /**
  55.          * 三层树结构中的第二层是一个ExpandableListView
  56.          */        
  57.         public View getChildView(int groupPosition, int childPosition,
  58.                         boolean isLastChild, View convertView, ViewGroup parent) {
  59.                 // 是 
  60.                 final ExpandableListView treeView = getExpandableListView();
  61.                 final TreeViewAdapter treeViewAdapter = new TreeViewAdapter(this.parentContext,0);
  62.                 List[tr] tmp = treeViewAdapter.GetTreeNode();//临时变量取得TreeViewAdapter的TreeNode集合,可为空
  63.                 final TreeNode treeNode=(TreeNode) getChild(groupPosition, childPosition);
  64.                 tmp.add(treeNode);
  65.                 treeViewAdapter.UpdateTreeNode(tmp);
  66.                 treeView.setAdapter(treeViewAdapter);
  67.                 
  68.                 //关键点:取得选中的二级树形菜单的父子节点,结果返回给外部回调函数
  69.                 treeView.setOnChildClickListener(this.stvClickEvent);
  70.                 
  71.                 /**
  72.                  * 关键点:第二级菜单展开时通过取得节点数来设置第三级菜单的大小
  73.                  */
  74.                 treeView.setOnGroupExpandListener(new OnGroupExpandListener() {
  75.                         @Override
  76.                         public void onGroupExpand(int groupPosition) {
  77.                                 
  78.                                 AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
  79.                                                 ViewGroup.LayoutParams.FILL_PARENT,
  80.                                                 (treeNode.childs.size()+1)*TreeViewAdapter.ItemHeight + 10);
  81.                                 treeView.setLayoutParams(lp);
  82.                         }
  83.                 });
  84.                 
  85.                 /**
  86.                  * 第二级菜单回收时设置为标准Item大小
  87.                  */
  88.                 treeView.setOnGroupCollapseListener(new OnGroupCollapseListener() {
  89.                         @Override
  90.                         public void onGroupCollapse(int groupPosition) {
  91.                                 
  92.                                 AbsListView.LayoutParams lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
  93.                                                 TreeViewAdapter.ItemHeight);
  94.                                 treeView.setLayoutParams(lp);
  95.                         }
  96.                 });
  97.                 treeView.setPadding(TreeViewAdapter.PaddingLeft, 0, 0, 0);
  98.                 return treeView;
  99.         }

  100.         /**
  101.          * 三级树结构中的首层是TextView,用于作为title
  102.          */
  103.         public View getGroupView(int groupPosition, boolean isExpanded,
  104.                         View convertView, ViewGroup parent) {
  105.                 TextView textView = TreeViewAdapter.getTextView(this.parentContext);
  106.                 textView.setText(getGroup(groupPosition).toString());
  107.                 textView.setPadding(TreeViewAdapter.PaddingLeft, 0, 0, 0);
  108.                 return textView;
  109.         }

  110.         public long getChildId(int groupPosition, int childPosition) {
  111.                 return childPosition;
  112.         }

  113.         public Object getGroup(int groupPosition) {
  114.                 return superTreeNodes.get(groupPosition).parent;
  115.         }

  116.         public int getGroupCount() {
  117.                 return superTreeNodes.size();
  118.         }

  119.         public long getGroupId(int groupPosition) {
  120.                 return groupPosition;
  121.         }

  122.         public boolean isChildSelectable(int groupPosition, int childPosition) {
  123.                 return true;
  124.         }

  125.         public boolean hasStableIds() {
  126.                 return true;
  127.         }
  128. }
复制代码

总结,使用ExpandableList实现三级树形菜单时有些bug不好解决,而且定义三维数组的时候也要倍加小心......所以尽量把数据化简来使用二级树形菜单。

转载地址:http://www.apkbus.com/android-23963-1-1.html

0 0
原创粉丝点击