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程序开发者,我一直觉得只 ...
随机推荐
- CDC ->> 在某个SQL Server中开启CDC功能
USE AdventureWorks;GO--开启某个数据库的CDC功能EXEC sys.sp_cdc_enable_db;GO--is_cdc_enabled栏位为1代表开启CDC功能了SELECT ...
- Java基本开发环境搭建
转http://blog.csdn.net/cxwen78/article/details/6400798 eclipse怎么编写JAVA,然后运行 1.新建一个Java project取个名字(首字 ...
- oracle11g 远程登录数据库
oracle11g 远程登录数据库比以往的任何版本都要简单,什么也不用做 1.OEM登录 在浏览器中直接输入,远程数据库的OEM网址,当然要把localhost或者主机名改成ip地址 https: ...
- 基于EntityFramework的权限的配置和验证
1. 概要 本文主要介绍公司现有系统框架的权限体系,和一些待扩展功能的说明.目前该权限体系基于角色构建(RBAC),原则上,系统中不允许出现对用户.组织等其他对象指派权限的情况. 2. 权限分 ...
- J2EE如何生成验证码图片和点击刷新验证码
验证码图片生成步骤 创建BufferedImage对象. 获取BufferedImage的画笔,即调用getGraphics()方法获取Graphics对象. 调用Graphics对象的setColo ...
- vim编辑器配置
原文链接:https://github.com/ma6174/vim http://my.oschina.net/swuly302/blog/156784?fromerr=itaFZFMb https ...
- poj-1017 Packets (贪心)
http://poj.org/problem?id=1017 工厂生产高度都为h,长和宽分别是1×1 2×2 3×3 4×4 5×5 6×6的6种规格的方形物品,交给顾客的时候需要包装,包装盒长宽高都 ...
- BZOJ 2754 喵星球上的点名(后缀数组)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2754 题意:给出n个字典串,m个询问串.输出每个询问串出现在多少个字典串中.最后输出每个 ...
- 什么是PHP Guzzle?
Guzzle是一个使得利用PHP实现发送HTTP 请求,方便和web service集成的PHP 客户端模拟组件.一句话,它就像一个PHP写的浏览器.当你的服务端程序需要作为客户端来访问其他的serv ...
- [ionic开源项目教程] - 第5讲 如何在项目中使用全局配置
第5讲 如何在项目中使用全局配置? Q:ionic开发,说纯粹一点,用的就是html+css+js,那么无疑跟web开发的方式是类似的.在这里给大家分享一个小技巧,如何在项目中使用全局配置? A:我的 ...