欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android提高之多级树形菜单的实现方法

程序员文章站 2022-11-05 14:56:18
一般来说在android里要实现树形菜单,都是用expandablelist(也有高手自己继承listview或者linearlayout来做),但是expandablel...

一般来说在android里要实现树形菜单,都是用expandablelist(也有高手自己继承listview或者linearlayout来做),但是expandablelist一般只能实现2级树形菜单。本文所述实例也依然使用expandablelist,但是要实现的是3级树形菜单。

本文程序运行效果图如下图所示:

Android提高之多级树形菜单的实现方法

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

static public class treenode{
 object parent;
 list<object> childs=new arraylist<object>();
}

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

static public class supertreenode {
 object parent;
 //二级树形菜单的结构体
 list<treeviewadapter.treenode> childs = new arraylist<treeviewadapter.treenode>();
}

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

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

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

此外还需要注意:本文在解决no.2关键点的时候,只能取得第三级选中的序号。而第一,第二级依然无法获取其序号。

main.xml源码如下:

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical" android:layout_width="fill_parent"
 android:layout_height="fill_parent">
 <linearlayout android:id="@+id/linearlayout01"
 android:layout_width="wrap_content" android:layout_height="wrap_content">
 <button android:layout_height="wrap_content" android:text="两层结构"
  android:layout_width="160dip" android:id="@+id/btnnormal"></button>
 <button android:layout_height="wrap_content" android:text="三层结构"
  android:layout_width="160dip" android:id="@+id/btnsuper"></button>
 </linearlayout>
 <expandablelistview android:id="@+id/expandablelistview01"
 android:layout_width="fill_parent" android:layout_height="fill_parent"></expandablelistview>
</linearlayout>

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

package com.testexpandablelist;
import java.util.list;
import android.app.activity;
import android.os.bundle;
import android.util.log;
import android.view.view;
import android.widget.button;
import android.widget.expandablelistview;
import android.widget.expandablelistview.onchildclicklistener;
import android.widget.toast;
public class testexpandablelist extends activity {
  /** called when the activity is first created. */
 expandablelistview expandablelist;
 treeviewadapter adapter;
 supertreeviewadapter superadapter;
 button btnnormal,btnsuper;
  // sample data set. children[i] contains the children (string[]) for groups[i].
  public string[] groups = { "xxxx好友", "xxxx同学", "xxxxx女人"};
  public string[][] child= {
      { "a君", "b君", "c君", "d君" },
      { "同学甲", "同学乙", "同学丙"},
      { "御姐", "萝莉" }
  };
  public string[] parent = { "xxxx好友", "xxxx同学"};
  public string[][][] child_grandson= {
   {{"a君"},
    {"aa","aaa"}},
   {{"b君"},
    {"bbb","bbbb","bbbbb"}},
   {{"c君"},
    {"ccc","cccc"}},
   {{"d君"},
    {"ddd","dddd","ddddd"}},
  };
  @override
  public void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.main);
    this.settitle("expandablelistview练习----hellogv");
    btnnormal=(button)this.findviewbyid(r.id.btnnormal);
    btnnormal.setonclicklistener(new clickevent());
    btnsuper=(button)this.findviewbyid(r.id.btnsuper);
    btnsuper.setonclicklistener(new clickevent());
    adapter=new treeviewadapter(this,treeviewadapter.paddingleft>>1);
    superadapter=new supertreeviewadapter(this,stvclickevent);
    expandablelist=(expandablelistview) testexpandablelist.this.findviewbyid(r.id.expandablelistview01);
  }
  class clickevent implements view.onclicklistener{
 @override
 public void onclick(view v) {
  adapter.removeall();
  adapter.notifydatasetchanged();
  superadapter.removeall();
  superadapter.notifydatasetchanged();
  
  if(v==btnnormal)
  {
     list<treeviewadapter.treenode> treenode = adapter.gettreenode();
     for(int i=0;i<groups.length;i++)
     {
      treeviewadapter.treenode node=new treeviewadapter.treenode();
      node.parent=groups[i];
      for(int ii=0;ii<child[i].length;ii++)
      {
      node.childs.add(child[i][ii]);
      }
      treenode.add(node);
     }
     adapter.updatetreenode(treenode);   
     expandablelist.setadapter(adapter);
     expandablelist.setonchildclicklistener(new onchildclicklistener(){
   @override
   public boolean onchildclick(expandablelistview arg0, view arg1,
   int parent, int children, long arg4) {
   string str="parent id:"+string.valueof(parent)+",children id:"+string.valueof(children);
   toast.maketext(testexpandablelist.this, str, 300).show();
   return false;
   }
     });
  }
  else if(v==btnsuper){
  list<supertreeviewadapter.supertreenode> supertreenode = superadapter.gettreenode();
     for(int i=0;i<parent.length;i++)//第一层
     {
      supertreeviewadapter.supertreenode supernode=new supertreeviewadapter.supertreenode();
      supernode.parent=parent[i];
      
      //第二层
      for(int ii=0;ii<child_grandson.length;ii++)
       {
        treeviewadapter.treenode node=new treeviewadapter.treenode();
        node.parent=child_grandson[ii][0][0];//第二级菜单的标题
        
        for(int iii=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);
  }
 }
  }
  /**
   * 三级树形菜单的事件不再可用,本函数由三级树形菜单的子项(二级菜单)进行回调
   */
  onchildclicklistener stvclickevent=new onchildclicklistener(){
 @override
 public boolean onchildclick(expandablelistview parent,
  view v, int groupposition, int childposition,
  long id) {
  string str="parent id:"+string.valueof(groupposition)+",children id:"+string.valueof(childposition);
  toast.maketext(testexpandablelist.this, str, 300).show();
  return false;
 }
  };
}

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

package com.testexpandablelist;
import java.util.arraylist;
import java.util.list;
import android.content.context;
import android.util.log;
import android.view.gravity;
import android.view.view;
import android.view.viewgroup;
import android.widget.abslistview;
import android.widget.baseexpandablelistadapter;
import android.widget.textview;
public class treeviewadapter extends baseexpandablelistadapter{
 public static final int itemheight=48;//每项的高度
 public static final int paddingleft=36;//每项的高度
 private int mypaddingleft=0;//如果是由supertreeview调用,则作为子项需要往右移
 static public class treenode{
 object parent;
 list<object> childs=new arraylist<object>();
 }
 list<treenode> treenodes = new arraylist<treenode>();
 context parentcontext;
 public treeviewadapter(context view,int mypaddingleft)
 {
 parentcontext=view;
 this.mypaddingleft=mypaddingleft;
 }
 public list<treenode> gettreenode()
 {
 return treenodes;
 }
 public void updatetreenode(list<treenode> nodes)
 {
 treenodes=nodes;
 }
 public void removeall()
 {
 treenodes.clear();
 }
 public object getchild(int groupposition, int childposition) {
 return treenodes.get(groupposition).childs.get(childposition);
 }
 public int getchildrencount(int groupposition) {
 return treenodes.get(groupposition).childs.size();
 }
 static public textview gettextview(context context) {
 abslistview.layoutparams lp = new abslistview.layoutparams(
  viewgroup.layoutparams.fill_parent, itemheight);
 textview textview = new textview(context);
 textview.setlayoutparams(lp);
 textview.setgravity(gravity.center_vertical | gravity.left);
 return textview;
 }
 public view getchildview(int groupposition, int childposition,
  boolean islastchild, view convertview, viewgroup parent) {
 textview textview = gettextview(this.parentcontext);
 textview.settext(getchild(groupposition, childposition).tostring());
 textview.setpadding(mypaddingleft+paddingleft, 0, 0, 0);
 return textview;
 }
 public view getgroupview(int groupposition, boolean isexpanded,
  view convertview, viewgroup parent) {
 textview textview = gettextview(this.parentcontext);
 textview.settext(getgroup(groupposition).tostring());
 textview.setpadding(mypaddingleft+(paddingleft>>1), 0, 0, 0);
 return textview;
 }
 public long getchildid(int groupposition, int childposition) {
 return childposition;
 }
 public object getgroup(int groupposition) {
 return treenodes.get(groupposition).parent;
 }
 public int getgroupcount() {
 return treenodes.size();
 }
 public long getgroupid(int groupposition) {
 return groupposition;
 }
 public boolean ischildselectable(int groupposition, int childposition) {
 return true;
 }
 public boolean hasstableids() {
 return true;
 }
}

supertreeviewadapter.java是实现三级树形菜单的工具类,会用到treeviewadapter.java,源码如下:

package com.testexpandablelist;
import java.util.arraylist;
import java.util.list;
import com.testexpandablelist.treeviewadapter.treenode;
import android.content.context;
import android.view.view;
import android.view.viewgroup;
import android.widget.abslistview;
import android.widget.baseexpandablelistadapter;
import android.widget.expandablelistview;
import android.widget.expandablelistview.onchildclicklistener;
import android.widget.expandablelistview.ongroupcollapselistener;
import android.widget.expandablelistview.ongroupexpandlistener;
import android.widget.textview;
public class supertreeviewadapter extends baseexpandablelistadapter {
 static public class supertreenode {
 object parent;
 //二级树形菜单的结构体
 list<treeviewadapter.treenode> childs = new arraylist<treeviewadapter.treenode>();
 }
 private list<supertreenode> supertreenodes = new arraylist<supertreenode>();
 private context parentcontext;
 private onchildclicklistener stvclickevent;//外部回调函数
 public supertreeviewadapter(context view,onchildclicklistener stvclickevent) {
 parentcontext = view;
 this.stvclickevent=stvclickevent;
 }
 public list<supertreenode> gettreenode() {
 return supertreenodes;
 }
 public void updatetreenode(list<supertreenode> node) {
 supertreenodes = node;
 }
 public void removeall()
 {
 supertreenodes.clear();
 }
 public object getchild(int groupposition, int childposition) {
 return supertreenodes.get(groupposition).childs.get(childposition);
 }
 public int getchildrencount(int groupposition) {
 return supertreenodes.get(groupposition).childs.size();
 }
 public expandablelistview getexpandablelistview() {
 abslistview.layoutparams lp = new abslistview.layoutparams(
  viewgroup.layoutparams.fill_parent, treeviewadapter.itemheight);
 expandablelistview supertreeview = new expandablelistview(parentcontext);
 supertreeview.setlayoutparams(lp);
 return supertreeview;
 }
 /**
 * 三层树结构中的第二层是一个expandablelistview
 */ 
 public view getchildview(int groupposition, int childposition,
  boolean islastchild, view convertview, viewgroup parent) {
 // 是 
 final expandablelistview treeview = getexpandablelistview();
 final treeviewadapter treeviewadapter = new treeviewadapter(this.parentcontext,0);
 list<treenode> tmp = treeviewadapter.gettreenode();//临时变量取得treeviewadapter的treenode集合,可为空
 final treenode treenode=(treenode) getchild(groupposition, childposition);
 tmp.add(treenode);
 treeviewadapter.updatetreenode(tmp);
 treeview.setadapter(treeviewadapter);
 //关键点:取得选中的二级树形菜单的父子节点,结果返回给外部回调函数
 treeview.setonchildclicklistener(this.stvclickevent);
 /**
  * 关键点:第二级菜单展开时通过取得节点数来设置第三级菜单的大小
  */
 treeview.setongroupexpandlistener(new ongroupexpandlistener() {
  @override
  public void ongroupexpand(int groupposition) {
  abslistview.layoutparams lp = new abslistview.layoutparams(
   viewgroup.layoutparams.fill_parent,
   (treenode.childs.size()+1)*treeviewadapter.itemheight + 10);
  treeview.setlayoutparams(lp);
  }
 });
 /**
  * 第二级菜单回收时设置为标准item大小
  */
 treeview.setongroupcollapselistener(new ongroupcollapselistener() {
  @override
  public void ongroupcollapse(int groupposition) {
  
  abslistview.layoutparams lp = new abslistview.layoutparams(viewgroup.layoutparams.fill_parent,
   treeviewadapter.itemheight);
  treeview.setlayoutparams(lp);
  }
 });
 treeview.setpadding(treeviewadapter.paddingleft, 0, 0, 0);
 return treeview;
 }
 /**
 * 三级树结构中的首层是textview,用于作为title
 */
 public view getgroupview(int groupposition, boolean isexpanded,
  view convertview, viewgroup parent) {
 textview textview = treeviewadapter.gettextview(this.parentcontext);
 textview.settext(getgroup(groupposition).tostring());
 textview.setpadding(treeviewadapter.paddingleft, 0, 0, 0);
 return textview;
 }
 public long getchildid(int groupposition, int childposition) {
 return childposition;
 }
 public object getgroup(int groupposition) {
 return supertreenodes.get(groupposition).parent;
 }
 public int getgroupcount() {
 return supertreenodes.size();
 }
 public long getgroupid(int groupposition) {
 return groupposition;
 }
 public boolean ischildselectable(int groupposition, int childposition) {
 return true;
 }
 public boolean hasstableids() {
 return true;
 }
}

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

希望本文所述代码对大家进行android程序设计有一定的帮助。