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<Node> children = new ArrayList<Node>();/** * 父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<Node> getChildren(){return children;}public void setChildren(List<Node> 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<T> extends BaseAdapter{protected Context mContext;/** * 存储所有可见的Node */protected List<Node> mNodes;protected LayoutInflater mInflater;/** * 存储所有的Node */protected List<Node> 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<T> 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(){@Overridepublic 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();// 刷新视图}}}@Overridepublic int getCount(){return mNodes.size();}@Overridepublic Object getItem(int position){return mNodes.get(position);}@Overridepublic long getItemId(int position){return position;}@Overridepublic 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 <T> List<Node> getSortedNodes(List<T> datas,int defaultExpandLevel) throws IllegalArgumentException,IllegalAccessException{List<Node> result = new ArrayList<Node>();// 将用户数据转化为List<Node>List<Node> nodes = convetData2Node(datas);// 拿到根节点List<Node> rootNodes = getRootNodes(nodes);// 排序以及设置Node间关系for (Node node : rootNodes){addNode(result, node, defaultExpandLevel, 1);}return result;}/** * 过滤出所有可见的Node *  * @param nodes * @return */public static List<Node> filterVisibleNode(List<Node> nodes){List<Node> result = new ArrayList<Node>();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 <T> List<Node> convetData2Node(List<T> datas)throws IllegalArgumentException, IllegalAccessException{List<Node> nodes = new ArrayList<Node>();Node node = null;for (T t : datas){int id = -1;int pId = -1;String label = null;Class<? extends Object> 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<Node> getRootNodes(List<Node> nodes){List<Node> root = new ArrayList<Node>();for (Node node : nodes){if (node.isRoot())root.add(node);}return root;}/** * 把一个节点上的所有的内容都挂上去 */private static void addNode(List<Node> 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);} elsenode.setIcon(-1);}}

  五、SimpleTreeAdapter类

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

public class SimpleTreeAdapter<T> extends TreeListViewAdapter<T>{   int[] resids = new int[]{R.drawable.delete,R.drawable.rename};List<mButton> btList = new ArrayList<mButton>();    PopupWindow popupWindow= new PopupWindow(mContext);;public SimpleTreeAdapter(ListView mTree, Context context, List<T> datas,int defaultExpandLevel) throws IllegalArgumentException,IllegalAccessException{super(mTree, context, datas, defaultExpandLevel);}@Overridepublic 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@Overridepublic 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<Bean> mDatas = new ArrayList<Bean>();private List<FileBean> mDatas2 = new ArrayList<FileBean>();private ListView mTree;private SimpleTreeAdapter<FileBean> mAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initDatas();mTree = (ListView) findViewById(R.id.id_tree);try{mAdapter = new SimpleTreeAdapter<FileBean>(mTree, this, mDatas2, 10);mAdapter.setOnTreeNodeClickListener(new OnTreeNodeClickListener(){@Overridepublic 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, "歌词一"));}}

  

更多相关文章

  1. Android无法自动创建USB打印机节点/dev/usb/lp0
  2. android 读取根目录下的文件或文件夹
  3. Android设备节点的动态管理
  4. 获得Android的SD卡根目录
  5. Android如何生成设备节点
  6. android 从Activity 获取 rootView 根节点
  7. Android之USB Camera摄像头节点后移
  8. Android清单文件详解(六) ---- 节点的属性

随机推荐

  1. Android(安卓)系统数据库编程学习日志
  2. Android(安卓)自定义属性 attr format取
  3. android 编译模块
  4. cross compile toolchain for arm/androi
  5. --------------------【Android】跑马灯
  6. Android编译出现DSL element android.dat
  7. AIR Native Extension的使用(Android)二
  8. Android全局变量使用
  9. Android知识体系总结(全方面覆盖Android
  10. Android(安卓)用axis2 webService产生jav