这是一个层级列表的源码,可以无限打造层级深度
1.Node类
package com.example.utils;
import java.util.ArrayList;
import java.util.List;
public class Node {
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>();
public Node(int id, int pid, String name) {
this.id = id;
this.pid = pid;
this.name = name;
}
public Node() {
}
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 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 expand) {
isExpand = expand;
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;
}
//是否为根节点
public boolean isRoot(){
return parent == null;
}
//判断父节点的收缩状态
public boolean isParentExpand(){
if (parent ==null){
return false;
}else {
return parent.isExpand();
}
}
//判断是否是叶节点
public boolean isLeaf(){
return children.size() == 0;
}
}
2.TreeHelper类
package com.example.utils;
import com.example.annotation.TreeNodeId;
import com.example.annotation.TreeNodeLabel;
import com.example.annotation.TreeNodepId;
import com.example.threedemo.R;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class ThreeHelper {
//将用户数据转化为树形数据
public static <T>List<Node> conver2Datas2Nodes(List<T> datas) throws IllegalAccessException {
List<Node> nodes = new ArrayList<>();
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(TreeNodeLabel.class) != null){
field.setAccessible(true);
lable = (String) field.get(t);
}
}
node = new Node(id,pid,lable);
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;
}
public static <T> List<Node> getSortedNodes(List<T> datas,int defaultExpandLexel) throws IllegalAccessException {
List<Node> result = new ArrayList<>();
List<Node> nodes = conver2Datas2Nodes(datas);
//获取根节点
List<Node> rootNodes = getRootNodes(nodes);
for (Node node: rootNodes){
addNode(result,node,defaultExpandLexel,1);
}
return result;
}
//过滤出可见的节点
public static List<Node> filterVisbileNodes(List<Node> nodes){
List<Node> reuslt = new ArrayList<>();
for (Node node : nodes){
if (node.isRoot() || node.isParentExpand()) {
setNodeIcon(node);
reuslt.add(node);
}
}
return reuslt;
}
//把一个节点的所有孩子节点放入rusult
private static void addNode(List<Node> result, Node node, int defaultExpandLexel, int currentLevel) {
result.add(node);
if (defaultExpandLexel >= currentLevel){
node.setExpand(true);
}
if (node.isLeaf()){
return;
}else {
for (int i = 0;i < node.getChildren().size();i ++){
addNode(result,node.getChildren().get(i),defaultExpandLexel,currentLevel + 1);
}
}
}
//从所有节点中获取根节点
private static List<Node> getRootNodes(List<Node> nodes) {
List<Node> root = new ArrayList<>();
for (Node node : nodes){
if (node.isRoot()){
root.add(node);
}
}
return root;
}
//为Node设置图标
private static void setNodeIcon(Node n) {
if (n.getChildren().size() > 0&& n.isExpand()){
n.setIcon(R.drawable.down);
}else if (n.getChildren().size() > 0&& !n.isExpand()){
n.setIcon(R.drawable.right);
}else {
n.setIcon(-1);
}
}
}
3.SimpleTreeListViewAdapter类
package com.example.utils.adapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.example.threedemo.R;
import com.example.utils.Node;
import com.example.utils.ThreeHelper;
import java.util.List;
public class SimpleTreeListViewAdapter<T> extends TreeListViewAdapter<T> {
public SimpleTreeListViewAdapter(ListView tree, Context context,
List<T> dates, int defaultExpandLevel) throws IllegalAccessException {
super(tree, context, dates, defaultExpandLevel);
}
@Override
public View getConvertView(Node node, int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null){
convertView = inflater.inflate(R.layout.list_item,parent,false);
holder = new ViewHolder();
holder.mIcon = (ImageView) convertView.findViewById(R.id.item_icon55);
holder.mText = (TextView) convertView.findViewById(R.id.item_text55);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
if (node.getIcon() == -1){
holder.mIcon.setVisibility(View.INVISIBLE);
}else {
holder.mIcon.setVisibility(View.VISIBLE);
holder.mIcon.setImageResource(node.getIcon());
}
holder.mText.setText(node.getName());
return convertView;
}
public void addExtraNode(int position, String toString) {
Node node = mVisbleNodes.get(position);
int index = mAllNodes.indexOf(node);
//存储
Node exNode = new Node(-1,node.getId(),toString);
exNode.setParent(node);
node.getChildren().add(exNode);
mAllNodes.add(index+1,exNode);
mVisbleNodes = ThreeHelper.filterVisbileNodes(mAllNodes);
notifyDataSetChanged();
}
private class ViewHolder{
ImageView mIcon;
TextView mText;
}
}
4.TreeListViewAdapter类
package com.example.utils.adapter;
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 com.example.utils.Node;
import com.example.utils.ThreeHelper;
import java.util.List;
public abstract class TreeListViewAdapter<T> extends BaseAdapter {
protected Context mContext;
protected List<Node> mAllNodes;
protected List<Node> mVisbleNodes;
protected LayoutInflater inflater;
protected ListView mTree;
public interface OnTreeNodeOnClickListener{
void onClck(Node node,int position);
}
private OnTreeNodeOnClickListener mLisitener;
public void setOnTreeNodeLisitener(OnTreeNodeOnClickListener mLisitener) {
this.mLisitener = mLisitener;
}
public TreeListViewAdapter(ListView tree, Context context, List<T> dates, int defaultExpandLevel) throws IllegalAccessException {
mContext = context;
inflater = LayoutInflater.from(context);
mAllNodes = ThreeHelper.getSortedNodes(dates,defaultExpandLevel);
mVisbleNodes = ThreeHelper.filterVisbileNodes(mAllNodes);
mTree = tree;
mTree.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
expandOrCollapse(position);
if (mLisitener != null){
mLisitener.onClck(mVisbleNodes.get(position),position);
}
}
});
}
//点击收缩或展开
private void expandOrCollapse(int position) {
Node n = mVisbleNodes.get(position);
if (n != null){
if (n.isLeaf()){
return;
}
n.setExpand(!n.isExpand());
mVisbleNodes = ThreeHelper.filterVisbileNodes(mAllNodes);
notifyDataSetChanged();
}
}
@Override
public int getCount() {
return mVisbleNodes.size();
}
@Override
public Object getItem(int i) {
return mVisbleNodes.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Node node = mVisbleNodes.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);
}
package com.example.bean;
import com.example.annotation.TreeNodeId;
import com.example.annotation.TreeNodeLabel;
import com.example.annotation.TreeNodepId;
public class FileBean {
@TreeNodeId
private int id;
@TreeNodepId
private int pid;
@TreeNodeLabel
private String lable;
public FileBean(int id, int pid, String lable) {
this.id = id;
this.pid = pid;
this.lable = lable;
}
private String desc;
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 getLable() {
return lable;
}
public void setLable(String lable) {
this.lable = lable;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package com.example.threedemo;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import com.example.bean.FileBean;
import com.example.bean.OrgBean;
import com.example.utils.Node;
import com.example.utils.adapter.SimpleTreeListViewAdapter;
import com.example.utils.adapter.TreeListViewAdapter;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView listView;
private SimpleTreeListViewAdapter<OrgBean> adapter;
private List<FileBean> mDatas;
//private List<OrgBean> mDatas2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = findViewById(R.id.listView);
initDate();
try {
adapter = new SimpleTreeListViewAdapter<OrgBean>(listView,this,mDatas2,0);
listView.setAdapter(adapter);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
initEvent();
}
private void initEvent(){
adapter.setOnTreeNodeLisitener(new TreeListViewAdapter.OnTreeNodeOnClickListener() {
@Override
public void onClck(Node node, int position) {
if (node.isLeaf()){
Toast.makeText(MainActivity.this,node.getName(),Toast.LENGTH_SHORT).show();
}
}
});
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(final AdapterView<?> adapterView, View view, final int position, long l) {
final EditText editText = new EditText(MainActivity.this);
new AlertDialog.Builder(MainActivity.this).setTitle("标题").setView(editText)
.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
adapter.addExtraNode(position,editText.getText().toString());
}
}).setNegativeButton("取消",null).show();
return true;
}
});
}
private void initDate() {
mDatas = new ArrayList<>();
FileBean fileBean = new FileBean(1,0,"根目录1");
mDatas.add(fileBean);
fileBean = new FileBean(2,0,"根目录2");
mDatas.add(fileBean);
fileBean = new FileBean(3,0,"根目录3");
mDatas.add(fileBean);
fileBean = new FileBean(4,1,"根目录1-1");
mDatas.add(fileBean);
fileBean = new FileBean(5,1,"根目录1-1");
mDatas.add(fileBean);
fileBean = new FileBean(6,5,"根目录1-2-1");
mDatas.add(fileBean);
fileBean = new FileBean(7,3,"根目录3-1");
mDatas.add(fileBean);
fileBean = new FileBean(8,3,"根目录3-2");
mDatas.add(fileBean);
}
}