1.开发原因

  在项目中经常需要一个需要一个树状框架,这是非常常见的控件。不过可能是谷歌考虑到android是手机系统,界面宽度有限,

所以只提供了只有二级的ExpandableListView。虽然这个控件可以满足很多需求,但是无数级的树在某些情况下还是需要的,所以我花了一天时间

(大部分时间都在调试动画去了,不过现在动画还有点问题,具体原因不明。。如果某位大神能找到原因灰常感谢)。

注:今早起来终于修复了最后一个bug,现在的动画效果已经非常完美了,等下就把加了注释的代码贴上来。

  2.原理

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

  3.上图

图片是gif,真实效果要更加流畅一些,但是bug也还在的,就是开始隐藏的节点无法获取高度,可以通过自己事先设置解决。

  3.代码

TreeView.java:

  1 package net.memornote.android.ui.view;  2   3 import java.util.ArrayList;  4 import java.util.Collection;  5 import java.util.List;  6 import java.util.Timer;  7 import java.util.TimerTask;  8   9 import android.content.Context; 10 import android.graphics.Rect; 11 import android.util.AttributeSet; 12 import android.view.View; 13 import android.view.animation.Animation; 14 import android.view.animation.Animation.AnimationListener; 15 import android.view.animation.ScaleAnimation; 16 import android.view.animation.TranslateAnimation; 17 import android.widget.LinearLayout; 18  19 public class TreeView extends LinearLayout{ 20      21 //    private List<TreeItem> items; 22     private List<TreeItem> sortedItems; 23     private int animTime; 24  25     public TreeView(Context context, AttributeSet attrs) { 26         super(context, attrs); 27         setOrientation(LinearLayout.VERTICAL); 28     } 29     /** 30      * initialize data,you must make sure that each item has parent except the top ones. 31      * @param items the data to show  32      * @param index the index of the tree to insert to 33      * @param viewHeight each view's height 34      * @param animTime if you want expand animation,  35      * you can set the time(ms) of animation,otherwise you can set 0. 36      *  37      */ 38     public void initData(Collection<TreeItem> items,int index){ 39          40         if(items==null||items.size()==0){ 41             return ; 42         } 43  44         sortItemList(items); 45          46         int size=sortedItems.size(); 47          48         initAddIndex=index<0?-Integer.MAX_VALUE:index; 49          50         for (int i=0;i<size;i++) { 51             TreeItem item=sortedItems.get(i); 52             recuseShow(item); 53         } 54          55     } 56      57     private boolean isAnim=false; 58     /** 59      * 这个方法还有很 严重的bug,无法使用。。 60      * 设置为0则关闭动画 61      * @param animTime 62      */ 63     public void enabledAnim(int animTime) { 64         if(animTime<0){ 65             isAnim=false; 66             return ; 67         } 68         this.animTime=animTime; 69         isAnim=true; 70     } 71      72     private int initAddIndex;  73      74     private void recuseShow(TreeItem item){ 75         View view=item.getView(); 76         addView(view,initAddIndex); 77         if(item.getParent()!=null){ 78             view.setVisibility(View.GONE); 79         }else { 80             view.setVisibility(View.VISIBLE); 81         } 82         initAddIndex++; 83         List<TreeItem> childrens=item.getChildrens(); 84         if(childrens.size()>0){ 85             for (TreeItem it : childrens) { 86                 recuseShow(it); 87             } 88         } 89     } 90      91     private void sortItemList(Collection<TreeItem> items) { 92         //把items按照层级关系存放,sortedItems只存放顶层的item 93         sortedItems=new ArrayList<TreeItem>(5); 94         for (TreeItem item : items) { 95             if(item.getParent()==null){ 96                 sortedItems.add(item); 97             }else { 98                 item.getParent().getChildrens().add(item); 99             }100         }101         102     }103     104     105     private int viewIndex=0;106     private int animHeight=0;107     private void addChild(TreeItem item,boolean isRecurse){108         if(item.getChildrens().size()>0){109             List<TreeItem> list=item.getChildrens();110             for (TreeItem it :    list) {111                 View view=it.getView();112                 if(view.isShown()){113                     continue;114                 }115                 viewIndex++;116                 view.setVisibility(View.VISIBLE);117                 if(isAnim){118                     animHeight-=it.getViewHeight();119                 }120                 it.nextIsExpand=true;121                 if(isRecurse){122                     addChild(it,true);123                 }124             }125         }126     }127     private int removeCount=0;128     private synchronized void removeChild(TreeItem item,boolean isRecurse){129         if(item.getChildrens().size()>0){130             List<TreeItem> list=item.getChildrens();131             for (TreeItem it :    list) {132                 View view=it.getView();133                 if(!view.isShown()){134                     continue;135                 }136                 137                 TranslateAnimation ta=new TranslateAnimation(0, 0, 0, 0);138                 ta.setFillBefore(true);139                 ta.setDuration(1000);140                 view.startAnimation(ta);141                 removeCount++;142                 view.setVisibility(View.GONE);143                 if(isAnim){144                     animHeight+=it.getViewHeight();145                 }146                 if(isRecurse){147                     removeChild(it,true);148                 }149             }150         }151     }152 153     private void animAdd(){154         TranslateAnimation ta=new TranslateAnimation(155                 Animation.ABSOLUTE, 0, 156                 Animation.ABSOLUTE, 0, 157                 Animation.ABSOLUTE, animHeight, 158                 Animation.ABSOLUTE, 0);159         ta.setFillBefore(true);160         ta.setFillAfter(false);161         ta.setDuration(animTime);162         163         for (int i = viewIndex+1; i < getChildCount(); i++) {164             View view=getChildAt(i);165             if(view.isShown()){166                 view.startAnimation(ta);167             }168         }169         animHeight=0;170     }171     private void animRemove(){172         TranslateAnimation ta=new TranslateAnimation(173                 Animation.ABSOLUTE, 0, 174                 Animation.ABSOLUTE, 0, 175                 Animation.ABSOLUTE, animHeight, 176                 Animation.ABSOLUTE, 0);177         ta.setFillAfter(false);178         ta.setFillBefore(true);179         ta.setDuration(animTime);180         181         int startAnimIndex;182         startAnimIndex=viewIndex+1;183         for (int i = startAnimIndex; i < getChildCount(); i++) {184             View view=getChildAt(i);185             if(view.isShown()){186                 view.startAnimation(ta);187             }188         }189         animHeight=0;190     }191     public void expand(TreeItem item){192         viewIndex=indexOfChild(item.getView());193         addChild(item,false);194         if(isAnim){195             animAdd();196         }197     }198     199 200     public void expandAllChildren(TreeItem item) {201         viewIndex=indexOfChild(item.getView());202         addChild(item,true);203         if(isAnim){204             animAdd();205         }206     }207     208     public void expandAll(){209         if(sortedItems==null){210             return ;211         }212         for (TreeItem item : sortedItems) {213             expandAllChildren(item);214         }215     }216     217     public void contractAllChildren(TreeItem item) {218         viewIndex=indexOfChild(item.getView())+1;219         removeChild(item,true);220         if(isAnim){221             animRemove();222         }223     }224     225     public void contractAll(){226         if(sortedItems==null){227             return ;228         }229         for (TreeItem item : sortedItems) {230             contractAllChildren(item);231         }232     }233     234     public void bind(TreeItem item) {235         if(item.nextIsExpand){236             expand(item);237         }else {238             contractAllChildren(item);239         }240         item.nextIsExpand=!item.nextIsExpand;241     }242     243     244 }
TreeView

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;    private int viewHeight;              public TreeItem(){}    /**     * 初始化TreeItem     * @param view     * @param parent     */    public TreeItem(View view, TreeItem parent) {        super();        this.view = view;        this.parent = parent;    }    /**     * 初始化TreeItem     * @param view     * @param parent     */    public TreeItem(View view, TreeItem parent,int viewHeight) {        super();        this.view = view;        this.parent = parent;        this.viewHeight=viewHeight;    }    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;    }}
TreeItem

测试代码:

 1 import java.util.ArrayList; 2 import java.util.List; 3  4 import net.yunstudio.util.view.treeview.TreeItem; 5 import net.yunstudio.util.view.treeview.TreeView; 6 import android.os.Bundle; 7 import android.app.Activity; 8 import android.view.Menu; 9 import android.view.View;10 import android.view.View.OnClickListener;11 import android.widget.Button;12 13 public class MainActivity extends Activity {14 15     private TreeView treeView;16     @Override17     protected void onCreate(Bundle savedInstanceState) {18         super.onCreate(savedInstanceState);19         setContentView(R.layout.activity_main);20         treeView=(TreeView) findViewById(R.id.treeview);21         List<TreeItem> items=new ArrayList<TreeItem>();22         23         initData(items);24         treeView.initData(items, 0);25         treeView.enabledAnim(500);26         27     }28     //初始化一些测试数据29     public void initData(List<TreeItem> items) {30         for (int i=0;i<10;i++) {31 //            TextView tv=new TextView(getActivity());32             Button button=new Button(this);33             button.setText("item"+i);34             final TreeItem item=new TreeItem(button, null);35             36             button.setOnClickListener(new OnClickListener() {37                 @Override38                 public void onClick(View v) {39                     treeView.bind(item);40                 }41             });42             43             items.add(item);44             45             if(i%2==0){46                 Button bt1=new Button(this);47                 bt1.setText("item"+i);48                 bt1.setClickable(true);49                 final TreeItem item_1=new TreeItem(bt1, item);50                 51                 bt1.setOnClickListener(new OnClickListener() {52                     @Override53                     public void onClick(View v) {54 55                         treeView.bind(item_1);56                     }57                 });58                 items.add(item_1);59                 60                 if(i%4==0){61                     Button bt_2=new Button(this);62                     bt_2.setText("item"+i);63                     bt_2.setClickable(true);64                     final TreeItem item_2=new TreeItem( bt_2, item_1);65                     66                     bt_2.setOnClickListener(new OnClickListener() {67                         @Override68                         public void onClick(View v) {69                             treeView.bind(item_2);70                         }71                     });72                     items.add(item_2);73                 }74                 75             }76             77             78         }79     }80 81     @Override82     public boolean onCreateOptionsMenu(Menu menu) {83         // Inflate the menu; this adds items to the action bar if it is present.84         getMenuInflater().inflate(R.menu.main, menu);85         return true;86     }87 88 }
View Code

源码下载:https://github.com/yzhen334/android_treeview

更多相关文章

  1. 一个有趣的android加载动画
  2. 【Android(安卓)UI设计与开发】第04期:引导界面(四)仿人人网V5.9.2
  3. Android(安卓)UI - 右侧滑动实现A-Z的快速定位
  4. Android模拟开关按钮点击打开动画(属性动画之平移动画)
  5. Android属性动画-Property Animation(四) 组合动画
  6. Android之增长的数字(仿支付宝资产数字)
  7. Android(安卓)Layout标签之 - viewStub,requestFocus,merge,include
  8. Android(安卓)补间动画之平移动画TranslateAnimation
  9. Android—启动内置APK和动态发送接收自定义广播

随机推荐

  1. Android(安卓)IPC原理分析小结
  2. Android(安卓)java与html js交互 html视
  3. 最封闭的开源系统:Android
  4. Android之单元测试学习
  5. [Hi3751V811][Android8.0]系统按键的转换
  6. 《Android学习指南》目录
  7. Android中ExpandableListView的使用(一)
  8. Android,谁动了我的内存(1)
  9. Android(安卓)ListView 去除各种颜色问题
  10. 第一章 JAVA入门(Android(安卓)版本历史)