通过对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无限级树状结构的更多相关文章

  1. openerp学习笔记 对象间关系【多对一(一对一)、一对多(主细结构)、多对多关系、自关联关系(树状结构)】

    1.多对一(一对一)关系:采购单与供应商之间的关系 'partner_id':fields.many2one('res.partner', 'Supplier', required=True, sta ...

  2. 树状结构Java模型、层级关系Java模型、上下级关系Java模型与html页面展示

    树状结构Java模型.层级关系Java模型.上下级关系Java模型与html页面展示 一.业务原型:公司的组织结构.传销关系网 二.数据库模型 很简单,创建 id 与 pid 关系即可.(pid:pa ...

  3. 分享使用NPOI导出Excel树状结构的数据,如部门用户菜单权限

    大家都知道使用NPOI导出Excel格式数据 很简单,网上一搜,到处都有示例代码. 因为工作的关系,经常会有处理各种数据库数据的场景,其中处理Excel 数据导出,以备客户人员确认数据,场景很常见. ...

  4. 由简入繁实现Jquery树状结构

    在项目中,我们经常会需要一些树状结构的样式来显示层级结构等,比如下图的样式,之前在学.net的时候可以直接拖个服务端控件过来直接使用非常方便.但是利用Jquery的一些插件,也是可以实现这些效果的,比 ...

  5. php实现树状结构无级分类

    php实现树状结构无级分类   ).",'树2-1-1-2')";mysql_query($sql);?>

  6. 使用Map辅助拼装树状结构,消除递归调用

    目前菜单或其他树状结构在数据库中的存储,多数是以一个parentid作为关联字段,以一维形式存储.使用时全部查询出来,然后在内存中拼装成树状结构.现在主要涉及的是拼装方法的问题. 一般可以进行 递归调 ...

  7. lua 怎样输出树状结构的table?

    为了让游戏前端数据输出更加条理,做了一个简单树状结构来打印数据. ccmlog.lua local function __tostring(value, indent, vmap) local str ...

  8. js List<Map> 将偏平化的数组转为树状结构并排序

    数据格式: [ { "id":"d3e8a9d6-e4c6-4dd8-a94f-07733d3c1b59", "parentId":&quo ...

  9. 浅谈oracle树状结构层级查询之start with ....connect by prior、level及order by

    浅谈oracle树状结构层级查询 oracle树状结构查询即层次递归查询,是sql语句经常用到的,在实际开发中组织结构实现及其层次化实现功能也是经常遇到的,虽然我是一个java程序开发者,我一直觉得只 ...

随机推荐

  1. 修改webapp底图

    从webapp目录可以看出地图归mapManager处理,所以在MapManager.js中找关于加载地图的方法, 很容易在里面找到showMap方法: 下面有另一个方法_showMap方法,查看定义 ...

  2. ArcGIS Engine -- 常用方法

    空间关系 计算两点间距离 feature平移 计算范围 得到点集合的n倍Envelope范围 查询 查询要素,返回多个要素union后的Geometry 查找图层 得到地图上图层列表 根据名称在地图上 ...

  3. 关于strlen

    strlen的实现是通过4个字节4个字节进行枚举,然后通过位运算来判断这4个字节中是否有一个字节含有0,这样的话,效率就提高了4倍. 这个效率提高是假设a&b&c&d与a&am ...

  4. Android 怎样把光标放在EditText中文本的末尾处?

    EditText et = (EditText)findViewById(R.id.inbox); et.setSelection(et.getText().length());

  5. Model元数据解析

    Model 元数据是针对数据类型的一种描述信息,主要用于控制数据类型本身及其成员属性在界面上的呈现方式,同时也为Model 绑定和验证提供必不可少的元数据信息.一个复杂数据类型通过属性的方式定义了一系 ...

  6. Echarts - js-20160611

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  7. code manager tools TotoiseSVN安装及使用

    TotoiseSVN安装及使用 TotoiseSVN官方下载地址:http://tortoisesvn.net/downloads.html TotoiseSVN安装:很简单,一路直下:就不在这说了, ...

  8. Hibernate 异常 —— Unable to instantiate default tuplize

    出现这个异常 —— Unable to instantiate default tuplizer ,是 Hibernate 的映射文件(*.hbm.xml)导致的.仔细检查一下工程里的映射文件吧. 笔 ...

  9. HeadFirst jsp 03 (MVC)

    创建一个小的 web 应用, mvc, 麻雀虽小, 五脏俱全 补1: servlet没有main()方法, 他们受控与另外一个Java应用, 这个Java应用称为 容器, tomcat就是这么一个容器 ...

  10. sdut2169Sequence(dp)

    http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2169 感觉是有递归思想的 dp[j]表示从1到 ...