通过对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. 如何在github上展示作品——为你的项目生成一个快速访问的网址如(DaisyWang88.github.io)

      (这里值针对Windos系统的,因为本人用的是Window系统,暂时没有条件在其他平台上测试)   1.创建命名为 <userName>.github.io的仓库.      这里的u ...

  2. 传统三层结构和MVC之于贫血模式和充血模式以及领域建模

      相信很多人跟我一样,一开始在使用贫血模式的三层结构:抽象出来一个贫血的实体封装,然后把对模型的所有操作,分离出来,分离到BLL层去,然后DALL层负责把这些操作和数据库产生映射,负责读写删改的操作 ...

  3. 从SDE库文件手工删除SDE图层(转载)

    转载自:http://gis-conquer.blog.sohu.com/164467560.html 一.前言    虽然Catalog能解决这种问题,但是在特殊情况下也许这种方法有点用途.    ...

  4. 【转】Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例

    原文地址:http://www.cnblogs.com/luankun0214/p/4421770.html 感谢网友的分享,记录下来只为学习. 1.重写equals方法实例   部分代码参考http ...

  5. 运用CodeSmith Studio实现C#项目构架

    http://www.cnblogs.com/iCaca/category/80950.html http://www.cnblogs.com/BlueBreeze/archive/2011/07/1 ...

  6. AOJ - 2224 Save your cat(最小生成树)

    http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=45524 NY在自己的花园里养了很多猫.有一天,一个巫婆在N个点设置了魔法,然 ...

  7. sqlserver取得本月一号

    select convert(datetime,convert(varchar(7),getdate(),120)+'-01',120) select convert(datetime,convert ...

  8. Linux同步机制 - 多线程开发总结

    1 对于CPU开销大的场景,能利用多核,就尽量利用多核(常常自以为某需求的运算量不大,且CPU足够快,就偷懒写个单线程,结果效率很低) 2 使用多线程的时候,默认是加锁的.在加锁保证业务正常的条件下, ...

  9. Spring MVC详细运行流程

  10. 51nod1476 括号序列的最小代价

    这题应该可以用费用流写吧?不过我想不出贪心来TAT.其实还是单调队列乱搞啊T_T //ÍøÉϵÄ̰ÐÄËã·¨ºÃÉñ°¡¡£¡£¡£ÎÒÖ»»áÓÃ×îС·ÑÓÃ×î´óÁ÷ÅÜTAT #in ...