• 自己实现的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

  • 相关阅读:
    DevExpress gridcontrol添加了复选框删除选中的多行/批量删除的方法
    PowerDesigner中在生成的数据库脚本中用name列替换comment列作为字段描述的方法
    int.TryParse 与 int.Parse 的区别
    .NET winform 的keypress事件中判断当用户按下的是哪个键
    XtraReport改变纸张方向
    .NET的 DataTable中某列求和
    SQL UNION 操作符
    如何在VUE中使用leaflet地图框架
    eslint+prettier 的 VSCode配置项
    前端使用Git 切换分支 查看线上远程,本地切换
  • 原文地址:https://www.cnblogs.com/Mr-Nobody/p/3527688.html
Copyright © 2020-2023  润新知