首先来一张萌萌哒的效果图(比较懒 - -)
然后是代码:
// Node package com.example.treeview.utils; import java.util.ArrayList; import java.util.List; public class Node { public Node() { super(); } public Node(int id, int pId, String name) { super(); this.id = id; this.pId = pId; this.name = name; } private int id; /** * 根节点的层级 */ private int pId = 0; private String name; /** * 树的层级 */ private int level; /** * 是否展开 */ private boolean isExpand = false; private int icon; private Node parent; private List<Node> children = new ArrayList<Node>(); /** * 判断是否为根节点 * * @return */ public boolean isRoot() { return parent == null; } public int getId() { return id; } /** * 判断当前父节点是否展开 * * @return */ public boolean isparentExpand() { if (parent == null) { return false; } else { return parent.isExpand; } } /** * 判断是否为叶节点 * * @return */ public boolean isLeaf() { return children.size() == 0; } 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; } /** * 得到当前节点的层级 * * @return */ 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) { 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; } }
//FileBean package com.example.treeview.bean; import com.example.treeview.utils.annotation.TreeNodeId; import com.example.treeview.utils.annotation.TreeNodeLable; import com.example.treeview.utils.annotation.TreeNodePid; public class FileBean { @TreeNodeId private int id; @TreeNodePid private int pId; @TreeNodeLable private String label; public FileBean(int id, int pId, String label) { super(); this.id = id; this.pId = pId; this.label = label; } private String desc; }
// 注解 package com.example.treeview.utils.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME.RUNTIME) public @interface TreeNodeId { } package com.example.treeview.utils.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME.RUNTIME) public @interface TreeNodeLable { } package com.example.treeview.utils.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME.RUNTIME) public @interface TreeNodePid { }
//TreeHelper package com.example.treeview.utils; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import com.example.treeview.utils.annotation.TreeNodeId; import com.example.treeview.utils.annotation.TreeNodeLable; import com.example.treeview.utils.annotation.TreeNodePid; public class TreeHelper { /** * 将用户的数据转化为树形数据 * * @param datas * @return * @throws IllegalArgumentException * @throws IllegalAccessException */ public static <T> List<Node> convertDatasNodes(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 lable = null; node = new Node(); Class clazz = t.getClass(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (field.getAnnotation(TreeNodeId.class) != null) { field.setAccessible(true); id = field.getInt(t); } if (field.getAnnotation(TreeNodePid.class) != null) { field.setAccessible(true); pId = field.getInt(t); } if (field.getAnnotation(TreeNodeLable.class) != null) { field.setAccessible(true); lable = (String) field.get(t); } } node = new Node(id, pId, lable); nodes.add(node); } /** * * 设置节点间的关系 */ 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()) { 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; } /** * 设置过滤出可见的节点 * @param nodes * @return */ public static List<Node> filterVisibleNodeS(List<Node> nodes){ List<Node> reuslt=new ArrayList<Node>(); for (Node node : nodes) { if (node.isRoot()||node.isparentExpand()) { setNodeIcon(node); reuslt.add(node); } } return reuslt; } /** * * @param datas * @return * @throws IllegalArgumentException * @throws IllegalAccessException */ public static <T> List<Node> getSortedNodes(List<T> datas,int defaultExpandLevel) throws IllegalAccessException, IllegalArgumentException{ List<Node> result=new ArrayList<Node>(); List<Node> nodes=convertDatasNodes(datas); List<Node> rootNodes=getRootNodes(nodes); for (Node node : rootNodes) { AddNode(result,node,defaultExpandLevel,1); } return result; } /** * 把一个节点的所有孩子节点都放入result * @param result * @param node * @param defaultExpandLevel * @param currentLevel */ 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); } } /** * 从所有节点中过滤出根节点 * @param nodes * @return */ 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; } /** * 为Node设置图标 * @param n */ private static void setNodeIcon(Node n) { if (n.getChildren().size()>0&&n.isExpand()) { n.setIcon(0); }else if(n.getChildren().size()>0&&!n.isExpand()){ n.setIcon(1); }else { n.setIcon(-1); } } }
//TreeListViewAdapter package com.example.treeview.adapter; import java.util.List; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.ListView; import com.example.treeview.utils.Node; import com.example.treeview.utils.TreeHelper; public abstract class TreeListViewAdapter<T> extends BaseAdapter { protected Context mContext; protected List<Node> mAllNodes; protected List<Node> mVisibleNodes; protected LayoutInflater mInflater; protected ListView mTree; /** * 设置Node的点击回调 * * @author az * */ private interface OnTreeNodeClickListener { void onClick(Node node, int position); } private OnTreeNodeClickListener mListener; public void setOnTreeNodeClickListener(OnTreeNodeClickListener mListener) { this.mListener = mListener; } public OnTreeNodeClickListener getmListener() { return mListener; } public void setmListener(OnTreeNodeClickListener mListener) { this.mListener = mListener; } public TreeListViewAdapter(ListView mTree, Context context, List<T> datas, int defaultExpandLevel) throws IllegalAccessException, IllegalArgumentException { this.mContext = context; this.mInflater = LayoutInflater.from(context); this.mAllNodes = TreeHelper.getSortedNodes(datas, defaultExpandLevel); this.mVisibleNodes = TreeHelper.filterVisibleNodeS(mAllNodes); this.mTree = mTree; this.mTree.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { expandOrCollapse(position); if (mListener != null) { mListener.onClick(mVisibleNodes.get(position), position); } } }); } /** * 点击收缩或者展开 * * @param position */ private void expandOrCollapse(int position) { Node n = mVisibleNodes.get(position); if (n != null) { if (n.isLeaf()) return; n.setExpand(!n.isExpand()); mVisibleNodes = TreeHelper.filterVisibleNodeS(mAllNodes); notifyDataSetChanged(); } } @Override public int getCount() { return mVisibleNodes.size(); } @Override public Object getItem(int position) { return mVisibleNodes.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { Node node=mVisibleNodes.get(position); convertView=getConvertView(node, position, convertView, parent); convertView.setPadding(node.getLevel()*30, 3, 3,3); return convertView; } public abstract View getConvertView(Node node,int position,View convertView,ViewGroup parent); }
//SimpleTreeListViewAdapter 继承TreeLivewAdapter方便使用 package com.example.treeview.adapter; import java.util.List; import com.example.threeview.R; import com.example.treeview.utils.Node; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; public class SimpleTreeListViewAdapter<T> extends TreeListViewAdapter<T> { public SimpleTreeListViewAdapter(ListView mTree, Context context, List<T> datas, int defaultExpandLevel) throws IllegalAccessException, IllegalArgumentException { super(mTree, context, datas, defaultExpandLevel); // TODO Auto-generated constructor stub } @Override public View getConvertView(Node node, int position, View convertView, ViewGroup parent) { ViewHolder holder=null; if (convertView==null) { convertView=mInflater.inflate(R.layout.list_item, parent,false); holder=new ViewHolder(); holder.mIcon=(ImageView) convertView.findViewById(R.id.iv_itemicon); holder.mText=(TextView) convertView.findViewById(R.id.tv_itemtext); convertView.setTag(holder); }else { holder=(ViewHolder) convertView.getTag(); } holder.mText.setText(node.getName()); return convertView; } private class ViewHolder{ ImageView mIcon; TextView mText; } }
//MainActivity package com.example.treeview; import java.util.ArrayList; import java.util.List; import com.example.threeview.R; import com.example.treeview.adapter.SimpleTreeListViewAdapter; import com.example.treeview.bean.FileBean; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.ListView; public class MainActivity extends Activity { private ListView mTree; private SimpleTreeListViewAdapter<FileBean> mAdapter; private List<FileBean> mDatas; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTree=(ListView) findViewById(R.id.lv); initDatas(); try { mAdapter=new SimpleTreeListViewAdapter<>(mTree, this, mDatas, 0); mTree.setAdapter(mAdapter); } catch (IllegalAccessException | IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void initDatas() { mDatas=new ArrayList<FileBean>(); FileBean bean=new FileBean(1, 0, "根1"); mDatas.add(bean); bean=new FileBean(2, 0, "根2"); mDatas.add(bean); bean=new FileBean(3, 1, "根1-1"); mDatas.add(bean); bean=new FileBean(4, 2, "根2-1"); mDatas.add(bean); } }
在上面的adapter里面有自定义的一个,使用方法:
mAdapter.setOnTreeNodeClickListener(new );
提供了一个OnClick方法:
onClick(Node node, int position)
参考:http://www.imooc.com/learn/303