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

自己实现的android树控件treeview

程序员文章站 2023-11-14 08:29:40
1.开发原因在项目中经常需要一个需要一个树状框架,这是非常常见的控件。不过可能是谷歌考虑到android是手机系统,界面宽度有限,所以只提供了只有二级的expandable...

1.开发原因
在项目中经常需要一个需要一个树状框架,这是非常常见的控件。不过可能是谷歌考虑到android是手机系统,界面宽度有限,所以只提供了只有二级的expandablelistview。虽然这个控件可以满足很多需求,但是无数级的树在某些情况下还是需要的,所以我花了一天时间(大部分时间都在调试动画去了,不过现在动画还有点问题,具体原因不明。。如果某位大神能找到原因灰常感谢)。

2.原理

网上很多都是扩展listview实现的,不过listview貌似不支持复杂控件的事件?而且做动画也不方便,所有我决定扩展linearlayout,在里面增加子节点的方式实现。

3.代码

treeview.java:

复制代码 代码如下:

 package net.memornote.android.ui.view;

 import java.util.arraylist;
 import java.util.list;
 import java.util.timer;
 import java.util.timertask;

 import android.content.context;
 import android.graphics.rect;
import android.util.attributeset;
import android.view.view;
import android.view.animation.animation;
import android.view.animation.animation.animationlistener;
import android.view.animation.scaleanimation;
import android.view.animation.translateanimation;
import android.widget.linearlayout;

public class treeview extends linearlayout{

//    private list<treeitem> items;
    private list<treeitem> sorteditems;
    private int animtime;

    public treeview(context context, attributeset attrs) {
        super(context, attrs);
        setorientation(linearlayout.vertical);
    }
    /**
     * initialize data,you must make sure that each item has parent except the top ones.
     * @param items the data to show
     * @param index the index of the tree to insert to
     * @param viewheight each view's height
     * @param animtime if you want expand animation,
     * you can set the time(ms) of animation,otherwise you can set 0.
     *
     */
    public void initdata(list<treeitem> items,int index){

        if(items==null||items.size()==0){
            return ;
        }

        sortitemlist(items);

        int size=sorteditems.size();

        initaddindex=index<0?-integer.max_value:index;

        for (int i=0;i<size;i++) {
            treeitem item=sorteditems.get(i);
            recuseshow(item);
        }

    }

    private boolean isanim=false;
    /**
     * 这个方法还有很 严重的bug,无法使用。。
     * 设置为0则关闭动画
     * @param animtime
     */
    public void enabledanim(int animtime) {
        if(animtime<0){
            isanim=false;
            return ;
        }
        this.animtime=animtime;
        isanim=true;
    }

    private int initaddindex;

    private void recuseshow(treeitem item){
        view view=item.getview();
        addview(view,initaddindex);
        if(item.getparent()!=null){
            view.setvisibility(view.gone);
            item.isshow=false;
        }else {
            view.setvisibility(view.visible);
            item.isshow=true;
        }
        initaddindex++;
        list<treeitem> childrens=item.getchildrens();
        if(childrens.size()>0){
            for (treeitem it : childrens) {
                recuseshow(it);
            }
        }
    }

    @override
    public void onwindowfocuschanged(boolean haswindowfocus) {
        super.onwindowfocuschanged(haswindowfocus);
        if(haswindowfocus){

        }
    }

   private void sortitemlist(list<treeitem> items) {
       //把items按照层级关系存放,sorteditems只存放顶层的item
       sorteditems=new arraylist<treeitem>(5);
       for (treeitem item : items) {
           if(item.getparent()==null){
               sorteditems.add(item);
           }else {
               item.getparent().getchildrens().add(item);
           }
       }

   }

  
   private int viewindex=0;
   private int animheight=0;
   private void addchild(treeitem item,boolean isrecurse){
       if(item.getchildrens().size()>0){
           list<treeitem> list=item.getchildrens();
           for (treeitem it :    list) {
               view view=it.getview();
               if(it.isshow){
                   continue;
               }
               viewindex++;
               view.setvisibility(view.visible);
               it.isshow=true;
               if(isanim){
                   animheight-=it.getviewheight();
               }
               it.nextisexpand=true;
               if(isrecurse){
                   addchild(it,true);
               }
           }
       }
   }
   private int removecount=0;
   private synchronized void removechild(treeitem item,boolean isrecurse){
       if(item.getchildrens().size()>0){
           list<treeitem> list=item.getchildrens();
           for (treeitem it :    list) {
               view view=it.getview();
               if(!it.isshow){
                   continue;
               }
//                removeviewat(viewindex);

               translateanimation ta=new translateanimation(0, 0, 0, 0);
               ta.setfillafter(true);
               ta.setduration(1000);
               view.startanimation(ta);
//                viewindex++;
               removecount++;
               it.isshow=false;
               view.setvisibility(view.gone);
               if(isanim){
                   animheight+=it.getviewheight();
               }
               if(isrecurse){
                   removechild(it,true);
               }
           }
       }
   }

   private void animadd(){
       translateanimation ta=new translateanimation(
               animation.absolute, 0,
               animation.absolute, 0,
               animation.absolute, animheight,
               animation.absolute, 0);
       ta.setfillbefore(true);
//        ta.setfillafter(false);
       ta.setduration(animtime);

       for (int i = viewindex+1; i < getchildcount(); i++) {
           view view=getchildat(i);
           view.startanimation(ta);
       }
       animheight=0;
   }
   private void animremove(){
       translateanimation ta=new translateanimation(
               animation.absolute, 0,
               animation.absolute, 0,
               animation.absolute, animheight,
               animation.absolute, 0);
       ta.setfillafter(false);
       ta.setfillbefore(true);
       ta.setduration(animtime);

       int startanimindex;
       startanimindex=viewindex+1;
       for (int i = startanimindex; i < getchildcount(); i++) {
           view view=getchildat(i);

           view.startanimation(ta);
       }
       animheight=0;
   }
   public void expand(treeitem item){
       viewindex=indexofchild(item.getview());
       addchild(item,false);
       if(isanim){
           animadd();
       }
   }
  

   public void expandallchildren(treeitem item) {
       viewindex=indexofchild(item.getview());
       addchild(item,true);
       if(isanim){
           animadd();
       }
   }

   public void expandall(){
       if(sorteditems==null){
           return ;
       }
       for (treeitem item : sorteditems) {
           expandallchildren(item);
       }
   }

   public void contractallchildren(treeitem item) {
       viewindex=indexofchild(item.getview())+1;
       removechild(item,true);
       if(isanim){
           animremove();
       }
   }

   public void contractall(){
       if(sorteditems==null){
           return ;
       }
       for (treeitem item : sorteditems) {
           contractallchildren(item);
       }
   }

   public void bind(treeitem item) {
       if(item.nextisexpand){
           expand(item);
       }else {
           contractallchildren(item);
       }
       item.nextisexpand=!item.nextisexpand;
   } 
}

treeitem.java

复制代码 代码如下:

package net.memornote.android.ui.view;

import java.util.arraylist;
import java.util.list;

import android.view.view;

public class treeitem {
    private view view;
   private treeitem parent;
   private list<treeitem> childrens=new arraylist<treeitem>(0);
   public boolean nextisexpand=true;
   public boolean isshow=false;
   private int viewheight; 

  
   public treeitem(){}
   public treeitem(int id,view view, treeitem parent) {
       super();
       this.view = view;
       this.parent = parent;
   }

   public view getview() {
       if(view!=null){
           view.setpadding(getlevel()*20,0,0,0);
       }
       return view;
   }

   public void setview(view view) {
       this.view = view;
   }

   public treeitem getparent() {
       return parent;
   }

   public void setparent(treeitem parent) {
       this.parent = parent;
   }

   /**
    * 动态获取该节点的级数
    * @return
    */
   public int getlevel() {
       int level=0;
       treeitem localparent=parent;

       while (localparent!=null) {
           level++;
           localparent=localparent.getparent();
       }

       return level;
   }
   public list<treeitem> getchildrens() {
       return childrens;
   }
   public int getviewheight() {
       if(view==null||view.getheight()==0){
           return viewheight;
       }
       return view.getheight();
   }
   public void setviewheight(int viewheight) {
       this.viewheight = viewheight;
   }
}

测试代码:

复制代码 代码如下:

package net.memornote.android.ui;

import net.memornote.android.r;
import net.memornote.android.ui.fragment.mainfragment;
import net.memornote.android.ui.fragment.menufragment;

import com.actionbarsherlock.view.menu;
import com.jeremyfeinstein.slidingmenu.lib.slidingmenu;
import com.jeremyfeinstein.slidingmenu.lib.app.slidingfragmentactivity;

import android.os.bundle;
import android.view.keyevent;

public class mainactivity extends slidingfragmentactivity {
   @override
   public void oncreate(bundle savedinstancestate) {
       super.oncreate(savedinstancestate);

       setcontentview(r.layout.slid_content_frame);

               tv_notebook=(treeview)   findviewbyid(r.id.tv_notebook);

       list<treeitem> items=new arraylist<treeitem>();

       initdata(items);
       tv_notebook.initdata(items, 0);
       tv_notebook.enabledanim(500);

   }
   //初始化一些测试数据
   public void initdata(list<treeitem> items) {
       for (int i=0;i<10;i++) {
//            textview tv=new textview(getactivity());
           button button=new button(getactivity());
           button.settext("item"+i);
           final treeitem item=new treeitem(0, button, null);

           button.setonclicklistener(new onclicklistener() {
               @override
               public void onclick(view v) {
                   tv_notebook.bind(item);
               }
           });

           items.add(item);

           if(i%2==0){
               button bt1=new button(getactivity());
               bt1.settext("item"+i);
               bt1.setclickable(true);
               final treeitem item_1=new treeitem(0, bt1, null);

               bt1.setonclicklistener(new onclicklistener() {
                   @override
                   public void onclick(view v) {

                       tv_notebook.bind(item_1);
                   }
               });
               item_1.setparent(item);
               items.add(item_1);

               if(i%4==0){
                   button bt_2=new button(getactivity());
                   bt_2.settext("item"+i);
                   bt_2.setclickable(true);
                   final treeitem item_2=new treeitem(0, bt_2, null);

                   bt_2.setonclicklistener(new onclicklistener() {
                       @override
                       public void onclick(view v) {
                           tv_notebook.bind(item_2);
                       }
                   });
                   item_2.setparent(item_1);
                   items.add(item_2);
               }

           }

          
       }
   }

   @override
   public boolean oncreateoptionsmenu(menu menu) {
       return true;
   }

}