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程序开发者,我一直觉得只 ...
随机推荐
- linux shell 命令学习(3) split - split a file into pieces
split 用来进行文件分割的指令 split [OPTION]... [INPUT [PREFIX]] 发现这个命令是因为有个需求,有个10W行的文本文件,需要分成5个2w行的文本文件, 查了一下资 ...
- 借助adb与gdb确认app内存缓存中是否存在用户敏感数据
一.环境准备 1. 搭建adb调试桥 可参考文章<ADB调试桥安装(方式二)> 2. 安装调试gdb工具 可参考文章<移动设备中导入gdb调试工具> 二.测试执行 root@G ...
- OpenJDK和OracleJDK的JVM性能有多大差距
首先要先明确OpenJDK和Sun/OracleJDK之间,以及OpenJDK 6.OpenJDK 7.OpenJDK 7u和OpenJDK 8等项目之间是什么关系,这有助于确定接下来编译要使用的JD ...
- CSS 滤镜(IE浏览器专属其他浏览器不支持)
Filter 属性介绍: 设置或检索对象所应用的滤镜或滤镜集合.此属性仅作用于有布局的对象,如块对象.内联要素要使用该属性,必须先设定对象的 height 或 width 属性,或者设定 positi ...
- laravel创建新model数据的两种方法
laravel中的CRUD操作中,通过对代表数据表中row的model对象操作,来更新数据库表. 对于创建新的row的操作,有两种功能上相同的方法: 1.create: $user = User::c ...
- R语言的向量化编程思维
1.计算缺失值比例 perNA<- mean(is.na(Data1)) 2.按值替换 #which返回值是符合条件的下标 NAIDX<- which(Data2<=3 | Data ...
- unity3d 破解安装
1.下载破解程序,执行生成unity_v4.x.ulf文件 2.断网 3.执行unity客户端,load该lisence文件即可 注意:安装unity客户端完成后,未破解,切记别打开unity客户端
- web服务器的相关资料 ngix
OpenResty:官方网站 http://openresty.org/cn/index.html 利用nginx+lua+memcache实现灰度发布 http://www.cnblogs.com ...
- 【转】Qt数据库总结
转自:http://blog.chinaunix.net/uid-25201977-id-3014100.html #include <QtSql>QT += sql QSqlDataba ...
- Spark源码阅读(1): Stage划分
Spark中job由action动作生成,那么stage是如何划分的呢?一般的解答是根据宽窄依赖划分.那么我们深入源码看看吧 一个action 例如count,会在多次runJob中传递,最终会到一个 ...