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