Android实现树形层级ListView
程序员文章站
2024-02-20 23:07:58
直接贴代码,代码中有相应注释:
主界面activity,布局就只一个listview:
public class mainactivity extends...
直接贴代码,代码中有相应注释:
主界面activity,布局就只一个listview:
public class mainactivity extends activity { private listview mlistview; private treelistviewadapter<testbean> madapter; private list<testbean> mdatas = new arraylist<testbean>(); @override protected void oncreate(bundle savedinstancestate) { // todo auto-generated method stub super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); this.mlistview = (listview) findviewbyid(r.id.listview); inittestdatas(); try { madapter = new treelistviewadapter<testbean>(mlistview, this, mdatas, 0); } catch (exception e) { e.printstacktrace(); } this.mlistview.setadapter(madapter); madapter.setmtreelistener(new treeviewonitemclick() { @override public void ontreeitemclick(int position, node node) { toast.maketext(mainactivity.this, "你点击的是:" + node.getname(), toast.length_short).show(); } }); this.mlistview.setonitemlongclicklistener(new onitemlongclicklistener() { @override public boolean onitemlongclick(adapterview<?> arg0, view arg1, final int arg2, long arg3) { final edittext edt = new edittext(mainactivity.this); new alertdialog.builder(mainactivity.this).settitle("insert").setview(edt).setpositivebutton("submit", new onclicklistener() { @override public void onclick(dialoginterface dialog, int which) { if (textutils.isempty(edt.gettext().tostring())) { toast.maketext(mainactivity.this, "请填写添加内容", toast.length_short).show(); } else { madapter.insertnodedata(arg2, edt.gettext().tostring()); } } }).setnegativebutton("cancel", null).create().show(); return true; } }); } private void inittestdatas() { testbean bean = null; bean = new testbean(1, 0, "文件目录1"); mdatas.add(bean); bean = new testbean(2, 0, "文件目录2"); mdatas.add(bean); bean = new testbean(3, 0, "文件目录3"); mdatas.add(bean); bean = new testbean(4, 1, "文件目录4"); mdatas.add(bean); bean = new testbean(5, 1, "文件目录5"); mdatas.add(bean); bean = new testbean(6, 2, "文件目录6"); mdatas.add(bean); bean = new testbean(7, 2, "文件目录7"); mdatas.add(bean); bean = new testbean(8, 3, "文件目录8"); mdatas.add(bean); bean = new testbean(9, 3, "文件目录9"); mdatas.add(bean); bean = new testbean(10, 0, "文件目录10"); mdatas.add(bean); } }
数据适配器基类:
** * 树形listview的数据适配器类 * @description: * @author ldm * @date 2015-10-9 上午9:47:01 */ public abstract class treeviewbaseadapter<t> extends baseadapter { protected context context; protected list<t> datas; protected list<node> mallnodes; protected list<node> mvisiblenodes; protected layoutinflater minflater; protected listview treelv; protected treeviewonitemclick mtreelistener; public treeviewbaseadapter(listview treelv, context context, list<t> datas, int defaultexpandlevel) throws illegalaccessexception, illegalargumentexception { this.context = context; this.treelv = treelv; minflater = layoutinflater.from(context); mallnodes = treehelpertools.getsortednodes(datas, defaultexpandlevel); mvisiblenodes = treehelpertools.filtervisiblenodes(mallnodes); this.treelv.setonitemclicklistener(new onitemclicklistener() { @override public void onitemclick(adapterview<?> arg0, view arg1, int position, long arg3) { expandorcollapse(position); if(mtreelistener!=null){ mtreelistener.ontreeitemclick(position, mvisiblenodes.get(position)); } } }); } public void setmtreelistener(treeviewonitemclick mtreelistener) { this.mtreelistener = mtreelistener; } /** * 设置listview点击item节点时,是否应该展开 * @description: * @author ldm * @date 2015-10-10 上午9:05:08 */ protected void expandorcollapse(int position) { node n=mvisiblenodes.get(position); if(n!=null){ if(n.isleaf()){ return; } n.setexpand(!n.isexpand()); mvisiblenodes=treehelpertools.filtervisiblenodes(mallnodes); notifydatasetchanged(); } } @override public int getcount() { // todo auto-generated method stub return mvisiblenodes.size(); } @override public object getitem(int position) { // todo auto-generated method stub return mvisiblenodes.get(position); } @override public long getitemid(int position) { // todo auto-generated method stub return position; } @override public view getview(int position, view convertview, viewgroup parent) { node node=mvisiblenodes.get(position); convertview = getcontentview(node,position, convertview, parent); return convertview; } public abstract view getcontentview(node node,int position, view convertview, viewgroup parent); public interface treeviewonitemclick{ void ontreeitemclick(int position,node node); } }
我们使用的adapter
public class treelistviewadapter<t> extends treeviewbaseadapter<t> { public treelistviewadapter(listview treelv, context context, list<t> datas, int defaultexpandlevel) throws illegalaccessexception, illegalargumentexception { super(treelv, context, datas, defaultexpandlevel); } @override public view getcontentview(node node, int position, view convertview, viewgroup parent) { viewholder holder = null; if (convertview == null) { holder = new viewholder(); convertview = minflater.inflate(r.layout.tree_listview_item, parent, false); holder.mitemiv = (imageview) convertview.findviewbyid(r.id.mitemiv); holder.mitemtv = (textview) convertview.findviewbyid(r.id.mitemtv); convertview.settag(holder); } else { holder = (viewholder) convertview.gettag(); } holder.mitemiv.setpadding(node.getlevel()*30, 3, 3, 3); if (node.geticon() == -1) { holder.mitemiv.setvisibility(view.invisible); } else { holder.mitemiv.setvisibility(view.visible); holder.mitemiv.setimageresource(node.geticon()); } holder.mitemtv.settext(node.getname()); return convertview; } private static class viewholder { imageview mitemiv; textview mitemtv; } /** * 动态插入数据 * @description: * @author ldm * @date 2015-10-10 上午10:08:03 */ public void insertnodedata(int position,string label) { node node=mvisiblenodes.get(position); int indexof=mallnodes.indexof(node); node insertnode=new node(-1, node.getid(), label); insertnode.setparent(node); node.getchildren().add(insertnode); mallnodes.add(indexof+1,insertnode); mvisiblenodes=treehelpertools.filtervisiblenodes(mvisiblenodes); notifydatasetchanged(); } }
数据处理的工具类:
public class treedatashelpertools { /** * 将用户提供的数据转化成树层级上可用数据 * @description: * @date 2015-10-9 下午4:07:24 */ public static <t> list<node> datas2nodes(list<t> datas) throws illegalaccessexception, illegalargumentexception { list<node> nodes = new arraylist<node>(); node node = null; for (t t : datas) { int id = -1; int pid = -1; string label = ""; // node = new node(); class clazz = t.getclass(); field[] fields = clazz.getdeclaredfields();// 反射获取类中的字段 for (field field : fields) { if (field.getannotation(treenodeid.class) != null) {// 根据字段上的注解来获取对应的值 field.setaccessible(true);// 在java的反射使用中,如果字段是私有的,那么必须要对这个字段设置才能正常使用,否则报错 id = field.getint(t); } if (field.getannotation(treenodepid.class) != null) { field.setaccessible(true); pid = field.getint(t); } if (field.getannotation(treenodelabel.class) != null) { field.setaccessible(true); label = (string) field.get(t); } } node = new node(id, pid, label); nodes.add(node); } // 设置nodes中的父子节点关系 for (int i = 0; i < nodes.size(); i++) { node n = nodes.get(i); for (int j = i + 1; j < nodes.size(); j++) { node m = nodes.get(j); if (m.getpid() == n.getid()) {// 如果m的父节点pid==n的id,则m是父节点,n是子节点 n.getchildren().add(m); m.setparent(n); } else if (m.getid() == n.getpid()) { m.getchildren().add(n); n.setparent(m); } } } // 设置节点图片 for (node n : nodes) { setnodeicon(n); } return nodes; } /** * 为我们的node数据设置对应的图标 * @description: * @date 2015-10-9 下午4:46:29 */ private static void setnodeicon(node n) { if (n.getchildren().size() > 0 && n.isexpand()) {// 如果有子节点且展开状态 n.seticon(r.drawable.icon_unable); } else if (n.getchildren().size() > 0 && !n.isexpand()) { n.seticon(r.drawable.icon_enable); } else { n.seticon(-1); } } public static <t> list<node> getsortednodes(list<t> datas, int defaultexpandlevel) throws illegalaccessexception, illegalargumentexception { list<node> result = new arraylist<node>(); list<node> nodes = datas2nodes(datas); // 首先获取根节点数据 list<node> rootnodes = getrootnodes(nodes); for (node node : rootnodes) { addnode(result, node, defaultexpandlevel, 1); } return result; }
/** * 获取数据中的所有根节点数据 * @description: * @date 2015-10-9 下午5:00:32 */ private static list<node> getrootnodes(list<node> nodes) { list<node> root = new arraylist<node>(); for (node node : nodes) { if (node.isroot()) { root.add(node); } } return root; } /** * 获取到可见的节点数据 * @description: * @date 2015-10-9 下午5:12:58 */ public static list<node> filtervisiblenodes(list<node> mallnodes) { list<node> nodes = new arraylist<node>(); for (node node : mallnodes) { if (node.isroot() || node.isparentexpand()) { setnodeicon(node); nodes.add(node); } } return nodes; } /** * 把一个节点的所有子节点都放入result中 * @description: * @date 2015-10-9 下午5:05:57 */ private static void addnode(list<node> result, node node, int defaultexpandlevel, int currentlevel) { result.add(node); if (defaultexpandlevel >= currentlevel) { node.setexpand(true); } if (node.isleaf()) { return; } for (int i = 0; i < node.getchildren().size(); i++) { addnode(result, node.getchildren().get(i), defaultexpandlevel, currentlevel + 1); } } }
数据实体bean:
public class testbean { @treenodeid private int id;//添加对应的注解 @treenodepid private int pid; @treenodelabel private string label; private string desc; public testbean(int id, int pid, string label) { super(); this.id = id; this.pid = pid; this.label = label; } public testbean() { // todo auto-generated constructor stub } public int getid() { return id; } public void setid(int id) { this.id = id; } public int getpid() { return pid; } public void setpid(int pid) { this.pid = pid; } public string getlabel() { return label; } public void setlabel(string label) { this.label = label; } public string getdesc() { return desc; } public void setdesc(string desc) { this.desc = desc; } }
数据展示中的node类,我们可以通过反射+注解把任意实体bean如testbean映射成我们想要的node
public class node { private int id;// 所在节点id private int pid = 0;// 父节点的id private string name;// 对应的内容 private int level;// 所在listview中树层级 private boolean isexpand = false;// 所在节点是否展开 private int icon;// 图标icon private node parent;// 父节点node private list<node> children = new arraylist<node>();// 对应的子节点数据集 public node() { } public node(int id, int pid, string name) { this.id = id; this.pid = pid; this.name = name; } public int getid() { return id; } public void setid(int id) { this.id = id; } public int getpid() { return pid; } public void setpid(int pid) { this.pid = pid; } public string getname() { return name; } public void setname(string name) { this.name = name; }
/** * 当前节点所在的层级 * @description: * @date 2015-10-9 下午4:02:29 */ public int getlevel() { return parent == null ? 0 : parent.getlevel() + 1; } public void setlevel(int level) { this.level = level; } public boolean isexpand() { return isexpand; } public void setexpand(boolean isexpand) { this.isexpand = isexpand; if (!isexpand && children.size() > 0) {// 如果当前节点没有展开,则其子节点展开状态也是:没展开 for (node node : children) { node.setexpand(false); } } } public int geticon() { return icon; } public void seticon(int icon) { this.icon = icon; } public node getparent() { return parent; } public void setparent(node parent) { this.parent = parent; } public list<node> getchildren() { return children; } public void setchildren(list<node> children) { this.children = children; } /** * 判断当前节点有没有子节点 * @description: * @author ldm * @date 2015-10-9 下午3:59:42 */ public boolean isleaf() { return children.size() == 0; } /** * 是不是根节点 * @description: * @author ldm * @date 2015-10-9 下午3:58:15 */ public boolean isroot() { return parent == null; } /** * 当前节点所在父节点是否展开 * @description: * @author ldm * @date 2015-10-9 下午3:58:34 */ public boolean isparentexpand() { if (parent == null) { return false; } else { return parent.isexpand; } } }
用到的注解类:
@target(elementtype.field)//定义注解的作用目标:字段、枚举的常量 @retention(retentionpolicy.runtime)//注解策略: 注解会在class字节码文件中存在,在运行时可以通过反射获取到 public @interface treenodeid { }
@target(elementtype.field)//定义注解的作用目标:字段、枚举的常量 @retention(retentionpolicy.runtime)//注解策略: 注解会在class字节码文件中存在,在运行时可以通过反射获取到 public @interface treenodelabel { } ``
@target(elementtype.field)//定义注解的作用目标:字段、枚举的常量 @retention(retentionpolicy.runtime)//注解策略: 注解会在class字节码文件中存在,在运行时可以通过反射获取到 public @interface treenodepid { }
以上就是android实现树形层级listview的相关代码,希望对大家的学习有所帮助。
推荐阅读
-
Android实现树形层级ListView
-
Android listview ExpandableListView实现多选,单选,全选,edittext实现批量输入的实例代码
-
安卓PopupWindow+ListView实现登录账号选择下拉框 博客分类: android开发 androidPopupWindow下拉框
-
Android编程实现动态更新ListView的方法
-
Android实现ListView数据动态加载的方法
-
Android实现上拉加载更多以及下拉刷新功能(ListView)
-
Android 中实现ListView滑动隐藏标题栏的代码
-
Android中ListView结合CheckBox实现数据批量选择(全选、反选、全不选)
-
Android中ListView结合CheckBox实现数据批量选择(全选、反选、全不选)
-
Android-自定义控件之ListView下拉刷新的实现