zoukankan      html  css  js  c++  java
  • 自己实现的android树控件,android TreeView

      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     @Override
    17     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                 @Override
    38                 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                     @Override
    53                     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                         @Override
    68                         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     @Override
    82     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

  • 相关阅读:
    1442. Count Triplets That Can Form Two Arrays of Equal XOR
    1441. Build an Array With Stack Operations
    312. Burst Balloons
    367. Valid Perfect Square
    307. Range Sum Query
    1232. Check If It Is a Straight Line
    993. Cousins in Binary Tree
    1436. Destination City
    476. Number Complement
    383. Ransom Note
  • 原文地址:https://www.cnblogs.com/Mr-Nobody/p/3527688.html
Copyright © 2011-2022 走看看