• Android无限级树状结构


    通过对ListView简单的扩展、再封装,即可实现无限层级的树控件TreeView。

      1 package cn.asiontang.nleveltreelistview;
      2 
      3 import android.annotation.TargetApi;
      4 import android.content.Context;
      5 import android.os.Build;
      6 import android.util.AttributeSet;
      7 import android.view.View;
      8 import android.widget.AdapterView;
      9 import android.widget.ListAdapter;
     10 import android.widget.ListView;
     11 
     12 /**
     13  * 支持N(无限)层级的树列表结构
     14  *
     15  * <p>参考资料:</p>
     16  * <ul>
     17  * <li>
     18  * <a href="http://item.congci.com/item/android-wuxian-ji-shuzhuang-jiegou">Android无限级树状结构 -
     19  * Android
     20  * - 从此网</a>
     21  * </li>
     22  * </ul>
     23  *
     24  * @author AsionTang
     25  * @since 2016年6月1日 18:38:43
     26  */
     27 @SuppressWarnings("unused")
     28 public class NLevelTreeView extends ListView
     29 {
     30     private OnTreeNodeClickListener mOnTreeNodeClickListener;
     31 
     32     public NLevelTreeView(final Context context)
     33     {
     34         super(context);
     35         this.init();
     36     }
     37 
     38     public NLevelTreeView(final Context context, final AttributeSet attrs)
     39     {
     40         super(context, attrs);
     41         this.init();
     42     }
     43 
     44     public NLevelTreeView(final Context context, final AttributeSet attrs, final int defStyleAttr)
     45     {
     46         super(context, attrs, defStyleAttr);
     47         this.init();
     48     }
     49 
     50     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     51     public NLevelTreeView(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes)
     52     {
     53         super(context, attrs, defStyleAttr, defStyleRes);
     54         this.init();
     55     }
     56 
     57     private void init()
     58     {
     59     }
     60 
     61     public void setAdapter(final NLevelTreeNodeAdapter adapter)
     62     {
     63         super.setAdapter(adapter);
     64 
     65         //让 NLevelTreeNodeAdapter 处理 节点 收缩展开 动作
     66         super.setOnItemClickListener(adapter);
     67 
     68         //处理当 叶子节点 被点击后的事件 回调。
     69         adapter.setOuterOnItemClickListener(new OnItemClickListener()
     70         {
     71             @Override
     72             public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id)
     73             {
     74                 if (NLevelTreeView.this.mOnTreeNodeClickListener != null)
     75                 {
     76                     final NLevelTreeNode item = (NLevelTreeNode) parent.getItemAtPosition(position);
     77                     NLevelTreeView.this.mOnTreeNodeClickListener.onTreeNodeClick(item);
     78                 }
     79             }
     80         });
     81     }
     82 
     83     /**
     84      * 必须使用继承自 NLevelTreeNodeAdapter 的 适配器,否则会出现异常。
     85      */
     86     @Override
     87     public void setAdapter(final ListAdapter adapter)
     88     {
     89         if (adapter instanceof NLevelTreeNodeAdapter)
     90             this.setAdapter((NLevelTreeNodeAdapter) adapter);
     91         else
     92             throw new RuntimeException("For NLevelTreeView, use setAdapter(NLevelTreeNodeAdapter) instead of setAdapter(ListAdapter)");
     93     }
     94 
     95     /**
     96      * 不支持使用此回调方式
     97      */
     98     @Override
     99     @Deprecated
    100     public void setOnItemClickListener(final OnItemClickListener listener)
    101     {
    102         //实际的事件回调在setAdapter里设置,由 setOnTreeNodeClickListener 处理。
    103         //super.setOuterOnItemClickListener(listener);
    104 
    105         throw new RuntimeException("For NLevelTreeView, use setOnTreeNodeClickListener() instead of setOnItemClickListener()");
    106     }
    107 
    108     /**
    109      * 默认只支持叶子节点的Click事件
    110      */
    111     public void setOnTreeNodeClickListener(final OnTreeNodeClickListener listener)
    112     {
    113         this.mOnTreeNodeClickListener = listener;
    114     }
    115 
    116     /**
    117      * 默认只支持叶子节点的Click事件
    118      */
    119     public interface OnTreeNodeClickListener
    120     {
    121         /**
    122          * 默认只支持叶子节点的Click事件
    123          */
    124         void onTreeNodeClick(NLevelTreeNode node);
    125     }
    126 }
    NLevelTreeView.java
     1 package cn.asiontang.nleveltreelistview;
     2 
     3 import android.content.Context;
     4 import android.view.View;
     5 import android.widget.AdapterView;
     6 
     7 import java.util.HashSet;
     8 import java.util.List;
     9 import java.util.Set;
    10 
    11 /**
    12  * @author AsionTang
    13  * @since 2016年6月1日 18:38:43
    14  */
    15 @SuppressWarnings("unused")
    16 public abstract class NLevelTreeNodeAdapter extends BaseAdapterEx3<NLevelTreeNode> implements AdapterView.OnItemClickListener
    17 {
    18     private final Set<NLevelTreeNode> mExpandedNodeList = new HashSet<>();
    19     private AdapterView.OnItemClickListener mOuterOnItemClickListener;
    20 
    21     public NLevelTreeNodeAdapter(final Context context, final int itemLayoutResId)
    22     {
    23         super(context, itemLayoutResId);
    24     }
    25 
    26     public NLevelTreeNodeAdapter(final Context context, final int itemLayoutResId, final List<NLevelTreeNode> objects)
    27     {
    28         super(context, itemLayoutResId, objects);
    29     }
    30 
    31     @Override
    32     public void convertView(final ViewHolder viewHolder, final NLevelTreeNode item)
    33     {
    34         this.convertView(viewHolder, item, this.mExpandedNodeList.contains(item));
    35     }
    36 
    37     public abstract void convertView(final ViewHolder viewHolder, final NLevelTreeNode item, boolean isExpanded);
    38 
    39     @Override
    40     public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id)
    41     {
    42         final NLevelTreeNode item = getItem(position);
    43         if (this.mExpandedNodeList.contains(item))
    44         {
    45             //把展开的节点,收缩起来
    46             this.mExpandedNodeList.remove(item);
    47 
    48             final int nextPosition = position + 1;
    49             while (true)
    50             {
    51                 //说明已经删除到最后一个节点了。
    52                 if (nextPosition >= this.getOriginaItems().size())
    53                     break;
    54 
    55                 final NLevelTreeNode tmpNode = this.getOriginaItems().get(nextPosition);
    56 
    57                 //只删除比它自己级别深的节点(如它的子、孙、重孙节点)
    58                 if (tmpNode.getLevel() <= item.getLevel())
    59                     break;
    60 
    61                 this.getOriginaItems().remove(tmpNode);
    62 
    63                 //防止它的子孙节点也有可能是展开的,所有也要移除其状态。
    64                 this.mExpandedNodeList.remove(tmpNode);
    65             }
    66             this.refresh();
    67         }
    68         else
    69         {
    70             //没有子节点,则不允许展开
    71             if (item.getChilds().size() == 0)
    72             {
    73                 //默认只支持叶子节点的Click事件
    74                 if (this.mOuterOnItemClickListener != null)
    75                     this.mOuterOnItemClickListener.onItemClick(parent, view, position, id);
    76                 return;
    77             }
    78 
    79             //把收缩的节点,展开起来
    80             this.mExpandedNodeList.add(item);
    81 
    82             this.getOriginaItems().addAll(position + 1, item.getChilds());
    83 
    84             this.refresh();
    85         }
    86     }
    87 
    88     /**
    89      * 设置外围调用者真正需要的 项点击OnItemClickListener 事件 回调。
    90      */
    91     protected void setOuterOnItemClickListener(final AdapterView.OnItemClickListener listener)
    92     {
    93         this.mOuterOnItemClickListener = listener;
    94     }
    95 }
    NLevelTreeNodeAdapter.java
      1 package cn.asiontang.nleveltreelistview;
      2 
      3 import java.util.ArrayList;
      4 import java.util.List;
      5 
      6 /**
      7  * @author AsionTang
      8  * @since 2016年6月1日 18:38:43
      9  */
     10 @SuppressWarnings("unused")
     11 public class NLevelTreeNode
     12 {
     13     private final List<NLevelTreeNode> mChilds = new ArrayList<>();
     14     private CharSequence mId;
     15     private int mLevel = 0;
     16     private CharSequence mName;
     17     private NLevelTreeNode mParentNode;
     18 
     19     public NLevelTreeNode()
     20     {
     21     }
     22 
     23     public NLevelTreeNode(final NLevelTreeNode parentNode, final int level, final CharSequence id, final CharSequence name)
     24     {
     25         this.setParentNode(parentNode);
     26         this.setLevel(level);
     27         this.setID(id);
     28         this.setName(name);
     29     }
     30 
     31     public NLevelTreeNode(final int level, final CharSequence id, final CharSequence name)
     32     {
     33         this(null, level, id, name);
     34     }
     35 
     36     public NLevelTreeNode(final CharSequence id, final CharSequence name)
     37     {
     38         this(null, 0, id, name);
     39     }
     40 
     41     public NLevelTreeNode(final CharSequence name)
     42     {
     43         this(null, 0, name, name);
     44     }
     45 
     46     /**
     47      * 为此Node添加一个子节点
     48      */
     49     public NLevelTreeNode addChild(final NLevelTreeNode child)
     50     {
     51         if (!this.mChilds.contains(child))
     52         {
     53             this.mChilds.add(child);
     54             child.setParentNode(this);
     55         }
     56         return this;
     57     }
     58 
     59     /**
     60      * 设置此Node所属的所有子节点
     61      */
     62     public NLevelTreeNode addChilds(final List<NLevelTreeNode> childs)
     63     {
     64         for (final NLevelTreeNode child : childs)
     65             this.addChild(child);
     66         return this;
     67     }
     68 
     69     /**
     70      * 获取此Node指定位置的子节点
     71      */
     72     public NLevelTreeNode getChild(final int index)
     73     {
     74         return this.mChilds.get(index);
     75     }
     76 
     77     /**
     78      * 获取此Node所属的所有子节点
     79      */
     80     public List<NLevelTreeNode> getChilds()
     81     {
     82         return this.mChilds;
     83     }
     84 
     85     /**
     86      * 获取当前Node 唯一标识符(当此Node被点击时,可供区分被点击的是谁)
     87      */
     88     public CharSequence getID()
     89     {
     90         return this.mId;
     91     }
     92 
     93     /**
     94      * 设置当前Node 唯一标识符(当此Node被点击时,可供区分被点击的是谁)
     95      */
     96     public NLevelTreeNode setID(final CharSequence id)
     97     {
     98         this.mId = id;
     99         return this;
    100     }
    101 
    102     /**
    103      * 获取当前Node所属哪个层级;一般从0级(根节点)开始递增。
    104      */
    105     public int getLevel()
    106     {
    107         return this.mLevel;
    108     }
    109 
    110     /**
    111      * 设置当前Node所在的层级;一般从0级(根节点)开始递增。
    112      */
    113     public NLevelTreeNode setLevel(final int level)
    114     {
    115         this.mLevel = level;
    116 
    117         //必须立即更新子节点的级别,否则就乱套了。
    118         for (final NLevelTreeNode child : this.mChilds)
    119             child.setLevel(level + 1);
    120         return this;
    121     }
    122 
    123     /**
    124      * 获取当前Node 名字
    125      */
    126     public CharSequence getName()
    127     {
    128         return this.mName;
    129     }
    130 
    131     /**
    132      * 设置当前Node 名字
    133      */
    134     public NLevelTreeNode setName(final CharSequence name)
    135     {
    136         this.mName = name;
    137         return this;
    138     }
    139 
    140     /**
    141      * 获取 此Note 的父节点
    142      */
    143     public NLevelTreeNode getParentNode()
    144     {
    145         return this.mParentNode;
    146     }
    147 
    148     /**
    149      * 设置 此Note 的父节点
    150      */
    151     public NLevelTreeNode setParentNode(final NLevelTreeNode parentNode)
    152     {
    153         this.mParentNode = parentNode;
    154         if (parentNode != null)
    155         {
    156             parentNode.addChild(this);
    157             this.setLevel(parentNode.getLevel() + 1);
    158         }
    159         return this;
    160     }
    161 }
    NLevelTreeNode.java

    源码:

    https://bitbucket.org/AsionTang/75.nleveltreeview/overview
    https://github.com/asiontang/75.NLevelTreeView

    作者:Asion Tang
    凡是没有注明[转载]的文章,本Blog发表的文章版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    day04 Java Web 开发入门
    day0203 XML 学习笔记
    canvas 基础
    TreeSet
    IntelliJ IDEA
    elastic-job-lite
    Spring 同一接口注入多个bean实现
    StringRedisTemplate
    小记
    linux 命令
  • 原文地址:https://www.cnblogs.com/AsionTang/p/5550895.html
Copyright © 2020-2023  润新知