当前位置: 移动技术网 > IT编程>移动开发>Android > Android实现树形层级ListView

Android实现树形层级ListView

2019年07月24日  | 移动技术网IT编程  | 我要评论

松原汽车站,环球雅思怎么样,揭秘日本女人和服里的震撼秘密

直接贴代码,代码中有相应注释:

主界面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的相关代码,希望对大家的学习有所帮助。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网