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

package cn.asiontang.nleveltreelistview; import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView; /**
* 支持N(无限)层级的树列表结构
*
* <p>参考资料:</p>
* <ul>
* <li>
* <a href="http://item.congci.com/item/android-wuxian-ji-shuzhuang-jiegou">Android无限级树状结构 -
* Android
* - 从此网</a>
* </li>
* </ul>
*
* @author AsionTang
* @since 2016年6月1日 18:38:43
*/
@SuppressWarnings("unused")
public class NLevelTreeView extends ListView
{
private OnTreeNodeClickListener mOnTreeNodeClickListener; public NLevelTreeView(final Context context)
{
super(context);
this.init();
} public NLevelTreeView(final Context context, final AttributeSet attrs)
{
super(context, attrs);
this.init();
} public NLevelTreeView(final Context context, final AttributeSet attrs, final int defStyleAttr)
{
super(context, attrs, defStyleAttr);
this.init();
} @TargetApi(Build.VERSION_CODES.LOLLIPOP)
public NLevelTreeView(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
this.init();
} private void init()
{
} public void setAdapter(final NLevelTreeNodeAdapter adapter)
{
super.setAdapter(adapter); //让 NLevelTreeNodeAdapter 处理 节点 收缩展开 动作
super.setOnItemClickListener(adapter); //处理当 叶子节点 被点击后的事件 回调。
adapter.setOuterOnItemClickListener(new OnItemClickListener()
{
@Override
public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id)
{
if (NLevelTreeView.this.mOnTreeNodeClickListener != null)
{
final NLevelTreeNode item = (NLevelTreeNode) parent.getItemAtPosition(position);
NLevelTreeView.this.mOnTreeNodeClickListener.onTreeNodeClick(item);
}
}
});
} /**
* 必须使用继承自 NLevelTreeNodeAdapter 的 适配器,否则会出现异常。
*/
@Override
public void setAdapter(final ListAdapter adapter)
{
if (adapter instanceof NLevelTreeNodeAdapter)
this.setAdapter((NLevelTreeNodeAdapter) adapter);
else
throw new RuntimeException("For NLevelTreeView, use setAdapter(NLevelTreeNodeAdapter) instead of setAdapter(ListAdapter)");
} /**
* 不支持使用此回调方式
*/
@Override
@Deprecated
public void setOnItemClickListener(final OnItemClickListener listener)
{
//实际的事件回调在setAdapter里设置,由 setOnTreeNodeClickListener 处理。
//super.setOuterOnItemClickListener(listener); throw new RuntimeException("For NLevelTreeView, use setOnTreeNodeClickListener() instead of setOnItemClickListener()");
} /**
* 默认只支持叶子节点的Click事件
*/
public void setOnTreeNodeClickListener(final OnTreeNodeClickListener listener)
{
this.mOnTreeNodeClickListener = listener;
} /**
* 默认只支持叶子节点的Click事件
*/
public interface OnTreeNodeClickListener
{
/**
* 默认只支持叶子节点的Click事件
*/
void onTreeNodeClick(NLevelTreeNode node);
}
}
NLevelTreeView.java
package cn.asiontang.nleveltreelistview; import android.content.Context;
import android.view.View;
import android.widget.AdapterView; import java.util.HashSet;
import java.util.List;
import java.util.Set; /**
* @author AsionTang
* @since 2016年6月1日 18:38:43
*/
@SuppressWarnings("unused")
public abstract class NLevelTreeNodeAdapter extends BaseAdapterEx3<NLevelTreeNode> implements AdapterView.OnItemClickListener
{
private final Set<NLevelTreeNode> mExpandedNodeList = new HashSet<>();
private AdapterView.OnItemClickListener mOuterOnItemClickListener; public NLevelTreeNodeAdapter(final Context context, final int itemLayoutResId)
{
super(context, itemLayoutResId);
} public NLevelTreeNodeAdapter(final Context context, final int itemLayoutResId, final List<NLevelTreeNode> objects)
{
super(context, itemLayoutResId, objects);
} @Override
public void convertView(final ViewHolder viewHolder, final NLevelTreeNode item)
{
this.convertView(viewHolder, item, this.mExpandedNodeList.contains(item));
} public abstract void convertView(final ViewHolder viewHolder, final NLevelTreeNode item, boolean isExpanded); @Override
public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id)
{
final NLevelTreeNode item = getItem(position);
if (this.mExpandedNodeList.contains(item))
{
//把展开的节点,收缩起来
this.mExpandedNodeList.remove(item); final int nextPosition = position + 1;
while (true)
{
//说明已经删除到最后一个节点了。
if (nextPosition >= this.getOriginaItems().size())
break; final NLevelTreeNode tmpNode = this.getOriginaItems().get(nextPosition); //只删除比它自己级别深的节点(如它的子、孙、重孙节点)
if (tmpNode.getLevel() <= item.getLevel())
break; this.getOriginaItems().remove(tmpNode); //防止它的子孙节点也有可能是展开的,所有也要移除其状态。
this.mExpandedNodeList.remove(tmpNode);
}
this.refresh();
}
else
{
//没有子节点,则不允许展开
if (item.getChilds().size() == 0)
{
//默认只支持叶子节点的Click事件
if (this.mOuterOnItemClickListener != null)
this.mOuterOnItemClickListener.onItemClick(parent, view, position, id);
return;
} //把收缩的节点,展开起来
this.mExpandedNodeList.add(item); this.getOriginaItems().addAll(position + 1, item.getChilds()); this.refresh();
}
} /**
* 设置外围调用者真正需要的 项点击OnItemClickListener 事件 回调。
*/
protected void setOuterOnItemClickListener(final AdapterView.OnItemClickListener listener)
{
this.mOuterOnItemClickListener = listener;
}
}
NLevelTreeNodeAdapter.java
package cn.asiontang.nleveltreelistview; import java.util.ArrayList;
import java.util.List; /**
* @author AsionTang
* @since 2016年6月1日 18:38:43
*/
@SuppressWarnings("unused")
public class NLevelTreeNode
{
private final List<NLevelTreeNode> mChilds = new ArrayList<>();
private CharSequence mId;
private int mLevel = 0;
private CharSequence mName;
private NLevelTreeNode mParentNode; public NLevelTreeNode()
{
} public NLevelTreeNode(final NLevelTreeNode parentNode, final int level, final CharSequence id, final CharSequence name)
{
this.setParentNode(parentNode);
this.setLevel(level);
this.setID(id);
this.setName(name);
} public NLevelTreeNode(final int level, final CharSequence id, final CharSequence name)
{
this(null, level, id, name);
} public NLevelTreeNode(final CharSequence id, final CharSequence name)
{
this(null, 0, id, name);
} public NLevelTreeNode(final CharSequence name)
{
this(null, 0, name, name);
} /**
* 为此Node添加一个子节点
*/
public NLevelTreeNode addChild(final NLevelTreeNode child)
{
if (!this.mChilds.contains(child))
{
this.mChilds.add(child);
child.setParentNode(this);
}
return this;
} /**
* 设置此Node所属的所有子节点
*/
public NLevelTreeNode addChilds(final List<NLevelTreeNode> childs)
{
for (final NLevelTreeNode child : childs)
this.addChild(child);
return this;
} /**
* 获取此Node指定位置的子节点
*/
public NLevelTreeNode getChild(final int index)
{
return this.mChilds.get(index);
} /**
* 获取此Node所属的所有子节点
*/
public List<NLevelTreeNode> getChilds()
{
return this.mChilds;
} /**
* 获取当前Node 唯一标识符(当此Node被点击时,可供区分被点击的是谁)
*/
public CharSequence getID()
{
return this.mId;
} /**
* 设置当前Node 唯一标识符(当此Node被点击时,可供区分被点击的是谁)
*/
public NLevelTreeNode setID(final CharSequence id)
{
this.mId = id;
return this;
} /**
* 获取当前Node所属哪个层级;一般从0级(根节点)开始递增。
*/
public int getLevel()
{
return this.mLevel;
} /**
* 设置当前Node所在的层级;一般从0级(根节点)开始递增。
*/
public NLevelTreeNode setLevel(final int level)
{
this.mLevel = level; //必须立即更新子节点的级别,否则就乱套了。
for (final NLevelTreeNode child : this.mChilds)
child.setLevel(level + 1);
return this;
} /**
* 获取当前Node 名字
*/
public CharSequence getName()
{
return this.mName;
} /**
* 设置当前Node 名字
*/
public NLevelTreeNode setName(final CharSequence name)
{
this.mName = name;
return this;
} /**
* 获取 此Note 的父节点
*/
public NLevelTreeNode getParentNode()
{
return this.mParentNode;
} /**
* 设置 此Note 的父节点
*/
public NLevelTreeNode setParentNode(final NLevelTreeNode parentNode)
{
this.mParentNode = parentNode;
if (parentNode != null)
{
parentNode.addChild(this);
this.setLevel(parentNode.getLevel() + 1);
}
return this;
}
}
NLevelTreeNode.java
源码:
https://bitbucket.org/AsionTang/75.nleveltreeview/overview
https://github.com/asiontang/75.NLevelTreeView
Android无限级树状结构的更多相关文章
- openerp学习笔记 对象间关系【多对一(一对一)、一对多(主细结构)、多对多关系、自关联关系(树状结构)】
1.多对一(一对一)关系:采购单与供应商之间的关系 'partner_id':fields.many2one('res.partner', 'Supplier', required=True, sta ...
- 树状结构Java模型、层级关系Java模型、上下级关系Java模型与html页面展示
树状结构Java模型.层级关系Java模型.上下级关系Java模型与html页面展示 一.业务原型:公司的组织结构.传销关系网 二.数据库模型 很简单,创建 id 与 pid 关系即可.(pid:pa ...
- 分享使用NPOI导出Excel树状结构的数据,如部门用户菜单权限
大家都知道使用NPOI导出Excel格式数据 很简单,网上一搜,到处都有示例代码. 因为工作的关系,经常会有处理各种数据库数据的场景,其中处理Excel 数据导出,以备客户人员确认数据,场景很常见. ...
- 由简入繁实现Jquery树状结构
在项目中,我们经常会需要一些树状结构的样式来显示层级结构等,比如下图的样式,之前在学.net的时候可以直接拖个服务端控件过来直接使用非常方便.但是利用Jquery的一些插件,也是可以实现这些效果的,比 ...
- php实现树状结构无级分类
php实现树状结构无级分类 ).",'树2-1-1-2')";mysql_query($sql);?>
- 使用Map辅助拼装树状结构,消除递归调用
目前菜单或其他树状结构在数据库中的存储,多数是以一个parentid作为关联字段,以一维形式存储.使用时全部查询出来,然后在内存中拼装成树状结构.现在主要涉及的是拼装方法的问题. 一般可以进行 递归调 ...
- lua 怎样输出树状结构的table?
为了让游戏前端数据输出更加条理,做了一个简单树状结构来打印数据. ccmlog.lua local function __tostring(value, indent, vmap) local str ...
- js List<Map> 将偏平化的数组转为树状结构并排序
数据格式: [ { "id":"d3e8a9d6-e4c6-4dd8-a94f-07733d3c1b59", "parentId":&quo ...
- 浅谈oracle树状结构层级查询之start with ....connect by prior、level及order by
浅谈oracle树状结构层级查询 oracle树状结构查询即层次递归查询,是sql语句经常用到的,在实际开发中组织结构实现及其层次化实现功能也是经常遇到的,虽然我是一个java程序开发者,我一直觉得只 ...
随机推荐
- ubuntu sh脚本双击运行
自从13.04以后,双击sh脚本文件就已经默认是geidt打开了,要想运行,从nautilus-->文件-->首选项-->行为-->可执行文件 有三个选项,默认是第二个,如果想 ...
- maven tomcat 插件实现热部署
tomcat 的maven插件有助于提高开发效率,原因是: --可以直接把项目发布到远程的服务器上. --能够实现项目的热部署,在开发过程中修改了Java类,不需要重启tomcat 首先配置一个tom ...
- Redis的Set操作
集合的性质: 唯一性,无序性,确定性 注: 在string和link的命令中,可以通过range 来访问string中的某几个字符或某几个元素 但,因为集合的无序性,无法通过下标或范围来访问部分元素. ...
- JVM垃圾回收机制总结(7) :调优方法
JVM调优工具 Jconsole,jProfile,VisualVM Jconsole : jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用.对垃圾回收算法有很详细的跟踪.详细说明参考这里 ...
- Linux命令-date
[root@localhost ~]# date 2016年 09月 07日 星期三 :: CST [root@localhost ~]# date "+%Y" [root@loc ...
- asp存储过程
dim s_ip,MyComm s_ip=request.ServerVariables("REMOTE_ADDR") Set MyComm = Server.CreateObje ...
- Android eMMC Booting
Android eMMC Booting Contents [hide] 1 eMMC binaries 1.1 Creating the GPT table 1.2 Modifying .IMG F ...
- Using Git subtrees to split a repository
https://lostechies.com/johnteague/2014/04/04/using-git-subtrees-to-split-a-repository/ We are in a p ...
- MongoDB 学习笔记(四)C# 操作MongoDB
C#驱动对mongodb的操作,目前驱动有两种:官方驱动和samus驱动,不过我个人还是喜欢后者, 因为提供了丰富的linq操作,相当方便. 官方驱动:https://github.com/mongo ...
- 《OD学hadoop》在LINUX下如何将tar压缩文件解压到指定的目录下
linux下tar命令解压到指定的目录 :#tar zxvf /bbs.tar.zip -C /zzz/bbs //把根目录下的bbs.tar.zip解压到/zzz/bbs下,前提要保证存在/zzz/ ...