Android 树形菜单

首先来一张萌萌哒的效果图(比较懒 - -)

然后是代码:

//  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

原文地址:https://www.cnblogs.com/stareblankly/p/5009871.html