Android实现树形层级ListView
直接贴代码,代码中有相应注释:
主界面Activity,布局就只一个ListView:
publicclassMainActivityextendsActivity{ privateListViewmListView; privateTreeListViewAdapter<TestBean>mAdapter; privateList<TestBean>mDatas=newArrayList<TestBean>(); @Override protectedvoidonCreate(BundlesavedInstanceState){ //TODOAuto-generatedmethodstub super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.mListView=(ListView)findViewById(R.id.listview); initTestDatas(); try{ mAdapter=newTreeListViewAdapter<TestBean>(mListView,this,mDatas,0); } catch(Exceptione){ e.printStackTrace(); } this.mListView.setAdapter(mAdapter); mAdapter.setmTreeListener(newTreeViewOnItemClick(){ @Override publicvoidonTreeItemClick(intposition,Nodenode){ Toast.makeText(MainActivity.this,"你点击的是:"+node.getName(),Toast.LENGTH_SHORT).show(); } }); this.mListView.setOnItemLongClickListener(newOnItemLongClickListener(){ @Override publicbooleanonItemLongClick(AdapterView<?>arg0,Viewarg1,finalintarg2,longarg3){ finalEditTextedt=newEditText(MainActivity.this); newAlertDialog.Builder(MainActivity.this).setTitle("Insert").setView(edt).setPositiveButton("submit",newOnClickListener(){ @Override publicvoidonClick(DialogInterfacedialog,intwhich){ 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(); returntrue; } }); } privatevoidinitTestDatas(){ TestBeanbean=null; bean=newTestBean(1,0,"文件目录1"); mDatas.add(bean); bean=newTestBean(2,0,"文件目录2"); mDatas.add(bean); bean=newTestBean(3,0,"文件目录3"); mDatas.add(bean); bean=newTestBean(4,1,"文件目录4"); mDatas.add(bean); bean=newTestBean(5,1,"文件目录5"); mDatas.add(bean); bean=newTestBean(6,2,"文件目录6"); mDatas.add(bean); bean=newTestBean(7,2,"文件目录7"); mDatas.add(bean); bean=newTestBean(8,3,"文件目录8"); mDatas.add(bean); bean=newTestBean(9,3,"文件目录9"); mDatas.add(bean); bean=newTestBean(10,0,"文件目录10"); mDatas.add(bean); } }
数据适配器基类:
** *树形ListView的数据适配器类 *@description: *@authorldm *@date2015-10-9上午9:47:01 */ publicabstractclassTreeViewBaseAdapter<T>extendsBaseAdapter{ protectedContextcontext; protectedList<T>datas; protectedList<Node>mAllNodes; protectedList<Node>mVisibleNodes; protectedLayoutInflatermInflater; protectedListViewtreeLv; protectedTreeViewOnItemClickmTreeListener; publicTreeViewBaseAdapter(ListViewtreeLv,Contextcontext,List<T>datas,intdefaultExpandLevel)throwsIllegalAccessException,IllegalArgumentException{ this.context=context; this.treeLv=treeLv; mInflater=LayoutInflater.from(context); mAllNodes=TreeHelperTools.getSortedNodes(datas,defaultExpandLevel); mVisibleNodes=TreeHelperTools.filterVisibleNodes(mAllNodes); this.treeLv.setOnItemClickListener(newOnItemClickListener(){ @Override publicvoidonItemClick(AdapterView<?>arg0,Viewarg1,intposition,longarg3){ expandOrCollapse(position); if(mTreeListener!=null){ mTreeListener.onTreeItemClick(position,mVisibleNodes.get(position)); } } }); } publicvoidsetmTreeListener(TreeViewOnItemClickmTreeListener){ this.mTreeListener=mTreeListener; } /** *设置ListView点击item节点时,是否应该展开 *@description: *@authorldm *@date2015-10-10上午9:05:08 */ protectedvoidexpandOrCollapse(intposition){ Noden=mVisibleNodes.get(position); if(n!=null){ if(n.isLeaf()){ return; } n.setExpand(!n.isExpand()); mVisibleNodes=TreeHelperTools.filterVisibleNodes(mAllNodes); notifyDataSetChanged(); } } @Override publicintgetCount(){ //TODOAuto-generatedmethodstub returnmVisibleNodes.size(); } @Override publicObjectgetItem(intposition){ //TODOAuto-generatedmethodstub returnmVisibleNodes.get(position); } @Override publiclonggetItemId(intposition){ //TODOAuto-generatedmethodstub returnposition; } @Override publicViewgetView(intposition,ViewconvertView,ViewGroupparent){ Nodenode=mVisibleNodes.get(position); convertView=getContentView(node,position,convertView,parent); returnconvertView; } publicabstractViewgetContentView(Nodenode,intposition,ViewconvertView,ViewGroupparent); publicinterfaceTreeViewOnItemClick{ voidonTreeItemClick(intposition,Nodenode); } }
我们使用的Adapter
publicclassTreeListViewAdapter<T>extendsTreeViewBaseAdapter<T>{ publicTreeListViewAdapter(ListViewtreeLv,Contextcontext,List<T>datas,intdefaultExpandLevel)throwsIllegalAccessException,IllegalArgumentException{ super(treeLv,context,datas,defaultExpandLevel); } @Override publicViewgetContentView(Nodenode,intposition,ViewconvertView,ViewGroupparent){ ViewHolderholder=null; if(convertView==null){ holder=newViewHolder(); 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()); returnconvertView; } privatestaticclassViewHolder{ ImageViewmItemIv; TextViewmItemTv; } /** *动态插入数据 *@description: *@authorldm *@date2015-10-10上午10:08:03 */ publicvoidinsertNodeData(intposition,Stringlabel){ Nodenode=mVisibleNodes.get(position); intindexOf=mAllNodes.indexOf(node); NodeinsertNode=newNode(-1,node.getId(),label); insertNode.setParent(node); node.getChildren().add(insertNode); mAllNodes.add(indexOf+1,insertNode); mVisibleNodes=TreeHelperTools.filterVisibleNodes(mVisibleNodes); notifyDataSetChanged(); } }
数据处理的工具类:
publicclassTreeDatasHelperTools{ /** *将用户提供的数据转化成树层级上可用数据 *@description: *@date2015-10-9下午4:07:24 */ publicstatic<T>List<Node>datas2Nodes(List<T>datas)throwsIllegalAccessException,IllegalArgumentException{ List<Node>nodes=newArrayList<Node>(); Nodenode=null; for(Tt:datas){ intid=-1; intpid=-1; Stringlabel=""; //node=newNode(); Classclazz=t.getClass(); Field[]fields=clazz.getDeclaredFields();//反射获取类中的字段 for(Fieldfield: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=newNode(id,pid,label); nodes.add(node); } //设置nodes中的父子节点关系 for(inti=0;i<nodes.size();i++){ Noden=nodes.get(i); for(intj=i+1;j<nodes.size();j++){ Nodem=nodes.get(j); if(m.getPid()==n.getId()){//如果m的父节点pid==n的id,则m是父节点,n是子节点 n.getChildren().add(m); m.setParent(n); } elseif(m.getId()==n.getPid()){ m.getChildren().add(n); n.setParent(m); } } } //设置节点图片 for(Noden:nodes){ setNodeIcon(n); } returnnodes; } /** *为我们的node数据设置对应的图标 *@description: *@date2015-10-9下午4:46:29 */ privatestaticvoidsetNodeIcon(Noden){ if(n.getChildren().size()>0&&n.isExpand()){//如果有子节点且展开状态 n.setIcon(R.drawable.icon_unable); } elseif(n.getChildren().size()>0&&!n.isExpand()){ n.setIcon(R.drawable.icon_enable); } else{ n.setIcon(-1); } } publicstatic<T>List<Node>getSortedNodes(List<T>datas,intdefaultExpandLevel)throwsIllegalAccessException,IllegalArgumentException{ List<Node>result=newArrayList<Node>(); List<Node>nodes=datas2Nodes(datas); //首先获取根节点数据 List<Node>rootNodes=getRootNodes(nodes); for(Nodenode:rootNodes){ addNode(result,node,defaultExpandLevel,1); } returnresult; }
/** *获取数据中的所有根节点数据 *@description: *@date2015-10-9下午5:00:32 */ privatestaticList<Node>getRootNodes(List<Node>nodes){ List<Node>root=newArrayList<Node>(); for(Nodenode:nodes){ if(node.isRoot()){ root.add(node); } } returnroot; } /** *获取到可见的节点数据 *@description: *@date2015-10-9下午5:12:58 */ publicstaticList<Node>filterVisibleNodes(List<Node>mAllNodes){ List<Node>nodes=newArrayList<Node>(); for(Nodenode:mAllNodes){ if(node.isRoot()||node.isParentExpand()){ setNodeIcon(node); nodes.add(node); } } returnnodes; } /** *把一个节点的所有子节点都放入result中 *@description: *@date2015-10-9下午5:05:57 */ privatestaticvoidaddNode(List<Node>result,Nodenode,intdefaultExpandLevel,intcurrentLevel){ result.add(node); if(defaultExpandLevel>=currentLevel){ node.setExpand(true); } if(node.isLeaf()){return;} for(inti=0;i<node.getChildren().size();i++){ addNode(result,node.getChildren().get(i),defaultExpandLevel,currentLevel+1); } } }
数据实体Bean:
publicclassTestBean{ @TreeNodeId privateintid;//添加对应的注解 @TreeNodePid privateintpid; @TreeNodeLabel privateStringlabel; privateStringdesc; publicTestBean(intid,intpid,Stringlabel){ super(); this.id=id; this.pid=pid; this.label=label; } publicTestBean(){ //TODOAuto-generatedconstructorstub } publicintgetId(){ returnid; } publicvoidsetId(intid){ this.id=id; } publicintgetPid(){ returnpid; } publicvoidsetPid(intpid){ this.pid=pid; } publicStringgetLabel(){ returnlabel; } publicvoidsetLabel(Stringlabel){ this.label=label; } publicStringgetDesc(){ returndesc; } publicvoidsetDesc(Stringdesc){ this.desc=desc; } }
数据展示中的Node类,我们可以通过反射+注解把任意实体bean如TestBean映射成我们想要的Node
publicclassNode{ privateintid;//所在节点id privateintpid=0;//父节点的id privateStringname;//对应的内容 privateintlevel;//所在ListView中树层级 privatebooleanisExpand=false;//所在节点是否展开 privateinticon;//图标icon privateNodeparent;//父节点Node privateList<Node>children=newArrayList<Node>();//对应的子节点数据集 publicNode(){ } publicNode(intid,intpid,Stringname){ this.id=id; this.pid=pid; this.name=name; } publicintgetId(){ returnid; } publicvoidsetId(intid){ this.id=id; } publicintgetPid(){ returnpid; } publicvoidsetPid(intpid){ this.pid=pid; } publicStringgetName(){ returnname; } publicvoidsetName(Stringname){ this.name=name; }
/** *当前节点所在的层级 *@description: *@date2015-10-9下午4:02:29 */ publicintgetLevel(){ returnparent==null?0:parent.getLevel()+1; } publicvoidsetLevel(intlevel){ this.level=level; } publicbooleanisExpand(){ returnisExpand; } publicvoidsetExpand(booleanisExpand){ this.isExpand=isExpand; if(!isExpand&&children.size()>0){//如果当前节点没有展开,则其子节点展开状态也是:没展开 for(Nodenode:children){ node.setExpand(false); } } } publicintgetIcon(){ returnicon; } publicvoidsetIcon(inticon){ this.icon=icon; } publicNodegetParent(){ returnparent; } publicvoidsetParent(Nodeparent){ this.parent=parent; } publicList<Node>getChildren(){ returnchildren; } publicvoidsetChildren(List<Node>children){ this.children=children; } /** *判断当前节点有没有子节点 *@description: *@authorldm *@date2015-10-9下午3:59:42 */ publicbooleanisLeaf(){ returnchildren.size()==0; } /** *是不是根节点 *@description: *@authorldm *@date2015-10-9下午3:58:15 */ publicbooleanisRoot(){ returnparent==null; } /** *当前节点所在父节点是否展开 *@description: *@authorldm *@date2015-10-9下午3:58:34 */ publicbooleanisParentExpand(){ if(parent==null){ returnfalse; } else{ returnparent.isExpand; } } }
用到的注解类:
@Target(ElementType.FIELD)//定义注解的作用目标:字段、枚举的常量 @Retention(RetentionPolicy.RUNTIME)//注解策略:注解会在class字节码文件中存在,在运行时可以通过反射获取到 public@interfaceTreeNodeId{ }
@Target(ElementType.FIELD)//定义注解的作用目标:字段、枚举的常量 @Retention(RetentionPolicy.RUNTIME)//注解策略:注解会在class字节码文件中存在,在运行时可以通过反射获取到 public@interfaceTreeNodeLabel{ } ``
@Target(ElementType.FIELD)//定义注解的作用目标:字段、枚举的常量 @Retention(RetentionPolicy.RUNTIME)//注解策略:注解会在class字节码文件中存在,在运行时可以通过反射获取到 public@interfaceTreeNodePid{ }
以上就是Android实现树形层级ListView的相关代码,希望对大家的学习有所帮助。