博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android多层树形结构列表学习笔记
阅读量:4686 次
发布时间:2019-06-09

本文共 13055 字,大约阅读时间需要 43 分钟。

    android中既有组件只有 expandlistview来实现二级的分级目录,但是如果是任意级的分级目录呢?今天看到了一个DEMO,学习一下~

    一、filebean类

   simpleadapter的数据源的数据单元(需转化为nodes),包含以下三个属性和构造函数

private int _id;	private int parentId;	private String name;	private long length;	public FileBean(int _id, int parentId, String name)	{		super();		this._id = _id;		this.parentId = parentId;		this.name = name;	}

  二、nodes类

  simpleadapter的数据源的数据单元(已转正),一大堆属性:ID、parentId、名称、级别、是否展开、下一级的孩子list、父节点、图标,可判断是否展开,是否为叶子节点,是否为根节点。

public class Node{	private int id;	/**	 * 根节点pId为0	 */	private int pId = 0;	private String name;	/**	 * 当前的级别	 */	private int level;	/**	 * 是否展开	 */	private boolean isExpand = false;	private int icon;	/**	 * 下一级的子Node	 */	private List
children = new ArrayList
(); /** * 父Node */ private Node parent; public Node() { } public Node(int id, int pId, String name) { super(); this.id = id; this.pId = pId; this.name = name; } public int getIcon() { return icon; } public void setIcon(int icon) { this.icon = icon; } 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; } public void setLevel(int level) { this.level = level; } public boolean isExpand() { return isExpand; } public List
getChildren() { return children; } public void setChildren(List
children) { this.children = children; } public Node getParent() { return parent; } public void setParent(Node parent) { this.parent = parent; } /** * 是否为跟节点 * * @return */ public boolean isRoot() { return parent == null; } /** * 判断父节点是否展开 * * @return */ public boolean isParentExpand() { if (parent == null) return false; return parent.isExpand(); } /** * 是否是叶子界点 * * @return */ public boolean isLeaf() { return children.size() == 0; } /** * 获取level */ public int getLevel() { return parent == null ? 0 : parent.getLevel() + 1; } /** * 设置展开 * * @param isExpand */ public void setExpand(boolean isExpand) { this.isExpand = isExpand; if (!isExpand) { for (Node node : children) { node.setExpand(isExpand); } } }}

  三、TreeListViewAdapter

    继承BaseAdapter的抽象类,主要控制listView的点击事件,并提供了获取convertview的抽象方法。

public abstract class TreeListViewAdapter
extends BaseAdapter{ protected Context mContext; /** * 存储所有可见的Node */ protected List
mNodes; protected LayoutInflater mInflater; /** * 存储所有的Node */ protected List
mAllNodes; /** * 点击的回调接口 */ private OnTreeNodeClickListener onTreeNodeClickListener; public interface OnTreeNodeClickListener { void onClick(Node node, int position); } public void setOnTreeNodeClickListener( OnTreeNodeClickListener onTreeNodeClickListener) { this.onTreeNodeClickListener = onTreeNodeClickListener; } /** * * @param mTree * @param context * @param datas * @param defaultExpandLevel * 默认展开几级树 * @throws IllegalArgumentException * @throws IllegalAccessException */ public TreeListViewAdapter(ListView mTree, Context context, List
datas, int defaultExpandLevel) throws IllegalArgumentException, IllegalAccessException { mContext = context; /** * 对所有的Node进行排序 */ mAllNodes = TreeHelper.getSortedNodes(datas, defaultExpandLevel); /** * 过滤出可见的Node */ mNodes = TreeHelper.filterVisibleNode(mAllNodes); mInflater = LayoutInflater.from(context); /** * 设置节点点击时,可以展开以及关闭;并且将ItemClick事件继续往外公布 */ mTree.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView
parent, View view, int position, long id) { expandOrCollapse(position); if (onTreeNodeClickListener != null) { onTreeNodeClickListener.onClick(mNodes.get(position), position); } } }); } /** * 相应ListView的点击事件 展开或关闭某节点 * * @param position */ public void expandOrCollapse(int position) { Node n = mNodes.get(position); if (n != null)// 排除传入参数错误异常 { if (!n.isLeaf()) { n.setExpand(!n.isExpand()); mNodes = TreeHelper.filterVisibleNode(mAllNodes); notifyDataSetChanged();// 刷新视图 } } } @Override public int getCount() { return mNodes.size(); } @Override public Object getItem(int position) { return mNodes.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { Node node = mNodes.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);}

  四、treehelper类

    提供了许多帮助我们的静态方法:

     convertData2Node:将传入的bean转化为node,并通过两两比较,得出他们父子间的关系。

     getRootNodes:遍历列表,筛选出root节点,返回父亲列表

     addNode:采用递归的方式,将属于一个父节点的子节点挂上去

     getSortedNodes:利用以上三个方法,将输入的无序nodes排列为层次分明的list

     filterVisibleNode:遍历列表,筛选出正在出现的notes,以此作为listview的填充数据(筛选的标准就是看expand)

     setNodeIcon:设置所有节点的icon,并根据是否展开设置不同的icon

public class TreeHelper{	/**	 * 传入我们的普通bean,转化为我们排序后的Node	 * 	 * @param datas	 * @param defaultExpandLevel	 * @return	 * @throws IllegalArgumentException	 * @throws IllegalAccessException	 */	public static 
List
getSortedNodes(List
datas, int defaultExpandLevel) throws IllegalArgumentException, IllegalAccessException { List
result = new ArrayList
(); // 将用户数据转化为List
List
nodes = convetData2Node(datas); // 拿到根节点 List
rootNodes = getRootNodes(nodes); // 排序以及设置Node间关系 for (Node node : rootNodes) { addNode(result, node, defaultExpandLevel, 1); } return result; } /** * 过滤出所有可见的Node * * @param nodes * @return */ public static List
filterVisibleNode(List
nodes) { List
result = new ArrayList
(); for (Node node : nodes) { // 如果为跟节点,或者上层目录为展开状态 if (node.isRoot() || node.isParentExpand()) { setNodeIcon(node); result.add(node); } } return result; } /** * 将我们的数据转化为树的节点 * * @param datas * @return * @throws NoSuchFieldException * @throws IllegalAccessException * @throws IllegalArgumentException */ private static
List
convetData2Node(List
datas) throws IllegalArgumentException, IllegalAccessException { List
nodes = new ArrayList
(); Node node = null; for (T t : datas) { int id = -1; int pId = -1; String label = null; Class
clazz = t.getClass(); Field[] declaredFields = clazz.getDeclaredFields(); for (Field f : declaredFields) { if (f.getAnnotation(TreeNodeId.class) != null) { f.setAccessible(true); id = f.getInt(t); } if (f.getAnnotation(TreeNodePid.class) != null) { f.setAccessible(true); pId = f.getInt(t); } if (f.getAnnotation(TreeNodeLabel.class) != null) { f.setAccessible(true); label = (String) f.get(t); } if (id != -1 && pId != -1 && label != null) { break; } } node = new Node(id, pId, label); nodes.add(node); } /** * 设置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; } private static List
getRootNodes(List
nodes) { List
root = new ArrayList
(); for (Node node : nodes) { if (node.isRoot()) root.add(node); } return root; } /** * 把一个节点上的所有的内容都挂上去 */ private static void addNode(List
nodes, Node node, int defaultExpandLeval, int currentLevel) { nodes.add(node); if (defaultExpandLeval >= currentLevel) { node.setExpand(true); } if (node.isLeaf()) return; for (int i = 0; i < node.getChildren().size(); i++) { addNode(nodes, node.getChildren().get(i), defaultExpandLeval, currentLevel + 1); } } /** * 设置节点的图标 * * @param node */ private static void setNodeIcon(Node node) { if (node.getChildren().size() > 0 && node.isExpand()) { node.setIcon(R.drawable.tree_ex); } else if (node.getChildren().size() > 0 && !node.isExpand()) { node.setIcon(R.drawable.tree_ec); } else node.setIcon(-1); }}

  五、SimpleTreeAdapter类

    listview的适配器,使用viewholder作为view的载体

public class SimpleTreeAdapter
extends TreeListViewAdapter
{ int[] resids = new int[]{R.drawable.delete,R.drawable.rename}; List
btList = new ArrayList
(); PopupWindow popupWindow= new PopupWindow(mContext);; public SimpleTreeAdapter(ListView mTree, Context context, List
datas, int defaultExpandLevel) throws IllegalArgumentException, IllegalAccessException { super(mTree, context, datas, defaultExpandLevel); } @Override public View getConvertView(Node node , int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (convertView == null) { convertView = mInflater.inflate(R.layout.list_item, parent, false); viewHolder = new ViewHolder(); viewHolder.icon = (ImageView) convertView .findViewById(R.id.id_treenode_icon); viewHolder.label = (TextView) convertView .findViewById(R.id.id_treenode_label); viewHolder.operate = (Button)convertView.findViewById(R.id.id_treenode_operate); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } if (node.getIcon() == -1) { viewHolder.icon.setVisibility(View.INVISIBLE); } else { viewHolder.icon.setVisibility(View.VISIBLE); viewHolder.icon.setImageResource(node.getIcon()); } viewHolder.label.setText(node.getName()); viewHolder.operate.setOnClickListener(new OnClickListener() { //以下设置管理按钮的点击事件添加解除popupwindow @Override public void onClick(View v) { // TODO Auto-generated method stub if (popupWindow.isShowing()) { Log.d("test", "coming"); popupWindow.dismiss(); //popupWindow = null; } else { LinearLayout pop_layout = (LinearLayout)mInflater.inflate(R.layout.pop_layout, null); fillButton(resids); for (mButton button: btList) { pop_layout.addView(button); } popupWindow.setContentView(pop_layout); popupWindow.setWidth(LayoutParams.WRAP_CONTENT); popupWindow.setHeight(LayoutParams.WRAP_CONTENT); popupWindow.showAtLocation((((MainActivity)mContext).findViewById(R.id.container)), Gravity.CENTER, 0, 0); Log.d("test2",String.valueOf(popupWindow.isShowing())); } } }); return convertView; } /** * 利用给定资源,定制button,并添加到btlist中 * */ private void fillButton(int[] resids){ if (!btList.isEmpty()) { btList.clear(); } for (int i = 0; i < resids.length; i++) { mButton button = ButtonUtil.getButton(mContext, i, resids[i]); btList.add(button); } } private final class ViewHolder { ImageView icon; TextView label; Button operate; }}

  六、mainactivity

      一个listview适配即可

public class MainActivity extends Activity{	private List
mDatas = new ArrayList
(); private List
mDatas2 = new ArrayList
(); private ListView mTree; private SimpleTreeAdapter
mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initDatas(); mTree = (ListView) findViewById(R.id.id_tree); try { mAdapter = new SimpleTreeAdapter
(mTree, this, mDatas2, 10); mAdapter.setOnTreeNodeClickListener(new OnTreeNodeClickListener() { @Override public void onClick(Node node, int position) { if (node.isLeaf()) { Toast.makeText(getApplicationContext(), node.getName(), Toast.LENGTH_SHORT).show(); } } }); } catch (Exception e) { e.printStackTrace(); } mTree.setAdapter(mAdapter); } private void initDatas() { mDatas.add(new Bean(1, 0, "根目录1")); mDatas.add(new Bean(2, 0, "根目录2")); mDatas.add(new Bean(3, 0, "根目录3")); mDatas.add(new Bean(4, 0, "根目录4")); mDatas.add(new Bean(5, 1, "子目录1-1")); mDatas.add(new Bean(6, 1, "子目录1-2")); mDatas.add(new Bean(7, 5, "子目录1-1-1")); mDatas.add(new Bean(8, 2, "子目录2-1")); mDatas.add(new Bean(9, 4, "子目录4-1")); mDatas.add(new Bean(10, 4, "子目录4-2")); mDatas.add(new Bean(11, 10, "子目录4-2-1")); mDatas.add(new Bean(12, 10, "子目录4-2-3")); mDatas.add(new Bean(13, 10, "子目录4-2-2")); mDatas.add(new Bean(14, 9, "子目录4-1-1")); mDatas.add(new Bean(15, 9, "子目录4-1-2")); mDatas.add(new Bean(16, 9, "子目录4-1-3")); mDatas2.add(new FileBean(1, 0, "音乐")); mDatas2.add(new FileBean(2, 1, "流行音乐")); mDatas2.add(new FileBean(3, 1, "爵士音乐")); mDatas2.add(new FileBean(4, 1, "古典音乐")); mDatas2.add(new FileBean(5, 2, "约定")); mDatas2.add(new FileBean(6, 2, "大男人")); mDatas2.add(new FileBean(7, 4, "bottoms up")); mDatas2.add(new FileBean(8, 4, "goodbye allis")); mDatas2.add(new FileBean(9, 7, "歌词一")); mDatas2.add(new FileBean(10, 7, "歌词二")); mDatas2.add(new FileBean(11, 7, "歌词三")); mDatas2.add(new FileBean(12, 8, "歌词一")); }}

  

转载于:https://www.cnblogs.com/gangmiangongjue/p/4567104.html

你可能感兴趣的文章
ArrayList和LinkedList和Vector源码分析
查看>>
webservice整合spring cxf
查看>>
再次编译这个应用程序应该不会有问题
查看>>
Ubuntu-tomcat7目录
查看>>
189. Rotate Array
查看>>
asp.net 的三种开发模式
查看>>
Android 交叉编译 IPerf3
查看>>
Android原生Gallery关于图像Orientation的问题
查看>>
[解题报告] 100 - The 3n + 1 problem
查看>>
Entity Framework 学习高级篇1—改善EF代码的方法(上)
查看>>
Mybatis逆向工程配置文件详细介绍(转)
查看>>
数组 Arrays类
查看>>
String类的深入学习与理解
查看>>
OLTP vs OLAP
查看>>
一些题目(3)
查看>>
Eclipse下配置主题颜色
查看>>
杂题 UVAoj 107 The Cat in the Hat
查看>>
ftp sun jdk自带
查看>>
python 元类——metaclass
查看>>
什么是缓冲,引入缓冲的原因是什么?
查看>>