Android实现TreeView

实现的效果图如下所示:


Android实现TreeView_第1张图片
image.png

1、定义Node节点对象

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class Node implements Serializable {

    private static final long serialVersionUID = -4492354830247617313L;

    //节点对象
    private B Bean;
    //节点id
    private T id;
    //节点对应的父级节点id,根节点的id为0
    private T pId;
    //节点名称
    private String name;
    //当前节点的级别
    private int level;
    //是否展开
    private boolean isExpand = false;
    //设置展开、关闭的图片
    private int icon = -1;
    //是否被选中
    private boolean isChecked;
    //子集
    private List children = new ArrayList<>();
    //父节点
    private Node parent;
    //节点文件下载状态
    private int status = 0;//0:未下载 1:已下载 2:正在下载

    public Node() {
    }

    public Node(T id, T pId, String name) {
        super();
        this.id = id;
        this.pId = pId;
        this.name = name;
    }

    public B getBean() {
        return Bean;
    }

    public void setBean(B bean) {
        Bean = bean;
    }

    public T getId() {
        return id;
    }

    public void setId(T id) {
        this.id = id;
    }

    public T getpId() {
        return pId;
    }

    public void setpId(T pId) {
        this.pId = pId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取level
     */
    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(isExpand);
            }
        }
    }

    public int getIcon() {
        return icon;
    }

    public void setIcon(int icon) {
        this.icon = icon;
    }

    public boolean isChecked() {
        return isChecked;
    }

    public void setChecked(boolean checked) {
        isChecked = checked;
    }

    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;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    /**
     * 是否为跟节点
     */
    public boolean isRoot() {
        return parent == null;
    }

    /**
     * 判断父节点是否展开
     */
    public boolean isParentExpand() {
        if (parent == null)
            return false;
        return parent.isExpand();
    }

    /**
     * 是否是叶子节点
     */
    public boolean isLeaf() {
        return children.size() == 0;
    }

}

2、定义TreeHelper

import android.text.TextUtils;

import com.glendale.bim.base.R;

import java.util.ArrayList;
import java.util.List;


/**
 * @user:CJJ-SAL
 * @time:2019/8/22 15:38
 * @desc:
 */
public class TreeHelper {

    /**
     * 返回排序后的节点树
     */
    public static List getSortedNodes(List datas, int defaultExpandLevel) {
        List result = new ArrayList();
        // 设置Node间父子关系
        List nodes = convetData2Node(datas);
        // 拿到根节点
        List rootNodes = getRootNodes(nodes);
        // 排序以及设置Node间关系
        for (Node node : rootNodes) {
            addNode(result, node, defaultExpandLevel, 1);
        }
        return result;
    }

    /**
     * 将我们的数据转化为树的节点
     */
    public static List convetData2Node(List datas) {
        for (int i = 0; i < datas.size(); i++) {
            Node n = datas.get(i);
            for (int j = i + 1; j < datas.size(); j++) {
                Node m = datas.get(j);
                if (m.getpId() instanceof String) {
                    String mId = (String) m.getId();
                    String mpId = (String) m.getpId();
                    String nId = (String) n.getId();
                    String npId = (String) n.getpId();

                    if (TextUtils.equals(mpId, nId)) {
                        n.getChildren().add(m);
                        m.setParent(n);
                    } else if (TextUtils.equals(mId, npId)) {
                        m.getChildren().add(n);
                        n.setParent(m);
                    }
                } else if (m.getpId() instanceof Integer) {
                    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);
                    }
                }
            }
        }
        return datas;
    }

    /**
     * 获取根节点
     */
    public static List getRootNodes(List datas) {
        List root = new ArrayList();
        for (Node node : datas) {
            if (node.isRoot())
                root.add(node);
        }
        return root;
    }

    /**
     * 通过递归的方式,把一个节点上的所有的子节点等都按顺序放入
     */
    public 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);
        }
    }

    /**
     * 过滤出所有可见的Node
     */
    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;
    }

    /**
     * 设置节点的图标
     */
    private static void setNodeIcon(Node node) {
        if (node.getChildren().size() > 0 && node.isExpand()) {
            node.setIcon(R.drawable.icon_node_expanding);
        } else if (node.getChildren().size() > 0 && !node.isExpand()) {
            node.setIcon(R.drawable.icon_node_no_expanding);
        } else {
            node.setIcon(-1);
        }
    }
}

3、实现ListView适配器

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

/**
 * @user:CJJ-SAL
 * @time:2019/8/22 15:14
 * @desc:
 */
public abstract class TreeListViewAdapter extends BaseAdapter {

    protected Context context;
    protected LayoutInflater mInflater;
    //存储所有可见的Node
    protected List mNodes = new ArrayList<>();
    //存储所有的Node
    protected List mAllNodes = new ArrayList<>();
    //节点点击接口
    private OnTreeNodeClickListener onTreeNodeClickListener;
    private OnTreeNodeLongClickListener onTreeNodeLongClickListener;
    //默认不展开
    private int defaultExpandLevel = 0;
    //展开与关闭的图片
    private int iconExpand = -1, iconNoExpand = -1;

    private List mDatas = new ArrayList<>();
    private ListView mTree;

    public TreeListViewAdapter(ListView mTree, Context context, List mDatas, int defaultExpandLevel) {
        this.mTree = mTree;
        this.context = context;
        this.mDatas = mDatas;
        this.defaultExpandLevel = defaultExpandLevel;
        initData();
    }

    public void initData() {
        if (null == mDatas || mDatas.size() == 0) {
            return;
        }
        mInflater = LayoutInflater.from(context);
        //对所有的Node进行排序
        mAllNodes = TreeHelper.getSortedNodes(mDatas, defaultExpandLevel);
        //过滤出可见的Node
        mNodes = TreeHelper.filterVisibleNode(mAllNodes);
        mTree.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id) {
                expandOrCollapse(position);
                if (onTreeNodeClickListener != null) {
                    onTreeNodeClickListener.onClick(mNodes.get(position), position);
                }
            }
        });
        mTree.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView parent, View view, int position, long id) {
                if (onTreeNodeLongClickListener != null) {
                    onTreeNodeLongClickListener.onLongClick(mNodes.get(position), position);
                }
                return true;
            }
        });
    }

    @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() * 20, 3, 3, 3);
        return convertView;
    }

    /**
     * 相应ListView的点击事件 展开或关闭某节点
     */
    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();// 刷新视图
            }
        }
    }

    /**
     * 设置节点选中状态
     *
     * @param node
     * @param isChecked
     */
    public void setChecked(Node node, boolean isChecked) {
        node.setChecked(isChecked);
        setChildChecked(node, isChecked);
        if (node.getParent() != null) {
            setNodeParentChecked(node.getParent(), isChecked);
        }
        notifyDataSetChanged();
    }

    /**
     * 获取排序后所有节点
     *
     * @return
     */
    public List getAllNodes() {
        if (mAllNodes == null)
            mAllNodes = new ArrayList();
        return mAllNodes;
    }

    /**
     * 设置子节点的选中状态
     *
     * @param node
     * @param isChecked
     * @param 
     * @param 
     */
    public  void setChildChecked(Node node, boolean isChecked) {
        if (!node.isLeaf()) {
            node.setChecked(isChecked);
            for (Node childrenNode : node.getChildren()) {
                setChildChecked(childrenNode, isChecked);
            }
        } else {
            node.setChecked(isChecked);
        }
    }

    /**
     * 设置节点的父级选中状态
     *
     * @param node
     * @param checked
     */
    private void setNodeParentChecked(Node node, boolean checked) {
        if (checked) {
            node.setChecked(checked);
            if (node.getParent() != null) {
                setNodeParentChecked(node.getParent(), checked);
            }
        } else {
            List childrens = node.getChildren();
            boolean isChecked = false;
            for (Node children : childrens) {
                if (children.isChecked()) {
                    isChecked = true;
                }
            }
            //如果所有子节点都没有被选中 父节点也不选中
            if (!isChecked) {
                node.setChecked(checked);
            }
            if (node.getParent() != null) {
                setNodeParentChecked(node.getParent(), checked);
            }
        }
    }

    public void setOnTreeNodeClickListener(OnTreeNodeClickListener onTreeNodeClickListener) {
        this.onTreeNodeClickListener = onTreeNodeClickListener;
    }

    public void setOnTreeNodeLongClickListener(OnTreeNodeLongClickListener onTreeNodeLongClickListener) {
        this.onTreeNodeLongClickListener = onTreeNodeLongClickListener;
    }

    public abstract View getConvertView(Node node, int position, View convertView, ViewGroup parent);

}

4、实现TreeRecyclerAdapter适配器

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

/**
 * @user:CJJ-SAL
 * @time:2019/11/21 11:48
 * @desc:
 */
public abstract class TreeRecyclerAdapter extends RecyclerView.Adapter {

    protected Context context;
    protected LayoutInflater mInflater;
    //存储所有可见的Node
    protected List mNodes = new ArrayList<>();
    //存储所有的Node
    protected List mAllNodes = new ArrayList<>();
    //节点点击接口
    private OnTreeNodeClickListener onTreeNodeClickListener;
    private OnTreeNodeLongClickListener onTreeNodeLongClickListener;
    //默认不展开
    private int defaultExpandLevel = 0;
    //展开与关闭的图片
    private int iconExpand = -1, iconNoExpand = -1;

    private List mDatas = new ArrayList<>();
    private RecyclerView mTree;

    public TreeRecyclerAdapter(RecyclerView mTree, Context context, List datas, int defaultExpandLevel) {
        setHasStableIds(true);
        this.mTree = mTree;
        this.context = context;
        this.mDatas = datas;
        this.defaultExpandLevel = defaultExpandLevel;
        initData();
    }

    public void initData() {
        if (null == mDatas || mDatas.size() == 0) {
            return;
        }
        mInflater = LayoutInflater.from(context);
        //对所有的Node进行排序
        mAllNodes = TreeHelper.getSortedNodes(mDatas, defaultExpandLevel);
        //过滤出可见的Node
        mNodes = TreeHelper.filterVisibleNode(mAllNodes);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {


        Node node = mNodes.get(position);
        // 设置内边距
        holder.itemView.setPadding(node.getLevel() * 20, 3, 3, 3);
        //设置点击事件
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                expandOrCollapse(position);
                if (onTreeNodeClickListener != null) {
                    onTreeNodeClickListener.onClick(mNodes.get(position), position);
                }
            }
        });
        //设置长按点击事件
        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (onTreeNodeLongClickListener != null) {
                    onTreeNodeLongClickListener.onLongClick(mNodes.get(position), position);
                }
                return true;
            }
        });
        onBindViewHolder(node, holder, position);
    }

    @Override
    public int getItemCount() {
        return mNodes.size();
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    /**
     * 相应ListView的点击事件 展开或关闭某节点
     */
    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();// 刷新视图
            }
        }
    }

    /**
     * 获取排序后所有节点
     *
     * @return
     */
    public List getAllNodes() {
        if (mAllNodes == null)
            mAllNodes = new ArrayList();
        return mAllNodes;
    }

    /**
     * 设置节点选中状态
     *
     * @param node
     * @param isChecked
     */
    public void setChecked(Node node, boolean isChecked) {
        node.setChecked(isChecked);
        setChildChecked(node, isChecked);
        if (node.getParent() != null) {
            setNodeParentChecked(node.getParent(), isChecked);
        }
        notifyDataSetChanged();
    }

    /**
     * 设置子节点的选中状态
     *
     * @param node
     * @param isChecked
     * @param 
     * @param 
     */
    public  void setChildChecked(Node node, boolean isChecked) {
        if (!node.isLeaf()) {
            node.setChecked(isChecked);
            for (Node childrenNode : node.getChildren()) {
                setChildChecked(childrenNode, isChecked);
            }
        } else {
            node.setChecked(isChecked);
        }
    }

    /**
     * 设置节点的父级选中状态
     *
     * @param node
     * @param checked
     */
    private void setNodeParentChecked(Node node, boolean checked) {
        if (checked) {
            node.setChecked(checked);
            if (node.getParent() != null) {
                setNodeParentChecked(node.getParent(), checked);
            }
        } else {
            List childrens = node.getChildren();
            boolean isChecked = false;
            for (Node children : childrens) {
                if (children.isChecked()) {
                    isChecked = true;
                }
            }
            //如果所有子节点都没有被选中 父节点也不选中
            if (!isChecked) {
                node.setChecked(checked);
            }
            if (node.getParent() != null) {
                setNodeParentChecked(node.getParent(), checked);
            }
        }
    }

    public void setOnTreeNodeClickListener(OnTreeNodeClickListener onTreeNodeClickListener) {
        this.onTreeNodeClickListener = onTreeNodeClickListener;
    }

    public void setOnTreeNodeLongClickListener(OnTreeNodeLongClickListener onTreeNodeLongClickListener) {
        this.onTreeNodeLongClickListener = onTreeNodeLongClickListener;
    }

    public abstract void onBindViewHolder(Node node, RecyclerView.ViewHolder holder, final int position);
}

5、定义节点的点击事件

/**
 * @user:CJJ-SAL
 * @time:2019/8/22 15:20
 * @desc:节点点击事件
 */
public interface OnTreeNodeClickListener {
    void onClick(Node node, int position);
}

/**
 * @user:CJJ-SAL
 * @time:2019/8/22 15:20
 * @desc:节点长按事件
 */
public interface OnTreeNodeLongClickListener {
    void onLongClick(Node node, int position);
}

6、可以使用下面的测试数据进行测试
测试数据如下:

[
 {
   "parentTaskId": "0",
   "taskId": "1",
   "taskName": "福建移动厦门数据中心",
   "taskType": 1,
   "taskFormType": 0
 },
 {
   "parentTaskId": "1",
   "taskId": "2",
   "taskName": "一层",
   "taskType": 2,
   "taskFormType": 0
 },
 {
   "parentTaskId": "2",
   "taskId": "3",
   "taskName": " 桩基",
   "taskType": 3,
   "taskFormType": 1
 },
 {
   "parentTaskId": "2",
   "taskId": "4",
   "taskName": "承台系梁",
   "taskType": 3,
   "taskFormType": 2
 },
 {
   "parentTaskId": "2",
   "taskId": "5",
   "taskName": "墩柱",
   "taskType": 3,
   "taskFormType": 3
 },
 {
   "parentTaskId": "2",
   "taskId": "6",
   "taskName": "盖梁",
   "taskType": 3,
   "taskFormType": 4
 },
 {
   "parentTaskId": "2",
   "taskId": "7",
   "taskName": "箱梁",
   "taskType": 3,
   "taskFormType": 5
 }
]
public class TestDemoAdapter extends TreeRecyclerAdapter {

    public TestDemoAdapter (RecyclerView mTree, Context context, List datas, int defaultExpandLevel) {
        super(mTree, context, datas, defaultExpandLevel);
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        GlTreeViewItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.gl_tree_view_item, parent, false);
        MyViewHolder holder = new MyViewHolder(binding.getRoot());
        holder.setBinding(binding);
        return holder;
    }

    @Override
    public void onBindViewHolder(Node node, RecyclerView.ViewHolder holder, int position) {
        MyViewHolder myViewHolder = (MyViewHolder) holder;
        myViewHolder.setData(node, position);
    }

    class MyViewHolder extends RecyclerView.ViewHolder {

        GlTreeViewItemBinding binding;

        public GlTreeViewItemBinding getBinding() {
            return binding;
        }

        public void setBinding(GlTreeViewItemBinding binding) {
            this.binding = binding;
        }

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
        }

        public void setData(Node node, int position) {
            //设置展开关闭的icon
            if (node.getIcon() == -1) {
                binding.imgTreeIcon.setVisibility(View.INVISIBLE);
            } else {
                binding.imgTreeIcon.setVisibility(View.VISIBLE);
                binding.imgTreeIcon.setImageResource(node.getIcon());
            }
            //设置父节点是否显示选择的控件
            binding.imgTreeChoose.setVisibility(View.GONE);
//            if (node.getChildren().size() > 0) {
//                binding.imgTreeChoose.setVisibility(View.GONE);
//            } else {
//                binding.imgTreeChoose.setVisibility(View.VISIBLE);
//            }
            //设置选中状态的icon
//            if (node.isChecked()) {//选中
//                node.setChecked(true);
//                binding.imgTreeChoose.setImageResource(R.drawable.ic_checkbox_checked);
//            } else {//未选中
//                node.setChecked(false);
//                binding.imgTreeChoose.setImageResource(R.drawable.ic_checkbox_uncheck);
//            }

//            binding.imgTreeChoose.setOnClickListener(new View.OnClickListener() {
//                @Override
//                public void onClick(View v) {
//                    boolean isChecked = node.isChecked();
//                    isChecked = !isChecked;
//                    LogUtil.E("是否选中:" + isChecked);
//                    node.setChecked(isChecked);
//                    //设置选中的状态
//                    //setChecked(node, isChecked);
//                    if (isChecked) {
//                        binding.imgTreeChoose.setImageResource(R.drawable.ic_checkbox_checked);
//                    } else {
//                        binding.imgTreeChoose.setImageResource(R.drawable.ic_checkbox_uncheck);
//                    }
//                    //节点选择结果回调接口
//                    if (null != onItemCheckedListener) {
//                        onItemCheckedListener.onSelectedNodes(node, position);
//                    }
//                }
//            });
            binding.textNodeName.setText(node.getName());
        }
    }

    //节点选择回调接口
    public interface OnItemCheckedListener {
        void onSelectedNodes(Node node, int position);
    }

    private OnItemCheckedListener onItemCheckedListener;

    public void setOnItemCheckedListener(OnItemCheckedListener onItemCheckedListener) {
        this.onItemCheckedListener = onItemCheckedListener;
    }
}

创建布局gl_tree_view_item




    

        

        

        

    


View层代码自己实现哦

你可能感兴趣的:(Android实现TreeView)