Android中RecyclerView实现多级列表

需求:实现出多级列表展示效果,每一级可点击,有子级展开子级数据,没有子级响应点击事件

说明:本文说的RecyclerView实现多级列表只是效果呈现是多级,实则是平行列表只有一级,当点击节点有子节点,则将子节点数据添加到该节点下边,每个子节点缩进指定距离(如下图)

以下附完整代码

build.gradle文件中引用RecyclerView

java 复制代码
dependencies {
	implementation 'com.android.support:recyclerview-v7:+'
}

activity_main.xml

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

item_multi_level.xml

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/iv_arrow"
        android:visibility="gone"
        android:layout_width="24dp"
        android:layout_height="24dp"
        android:layout_marginEnd="8dp"
         /><!--可添加自己所用展开、收起图片-->
    <TextView
        android:id="@+id/tv_item_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:textColor="@android:color/black" />

</LinearLayout>

TreeNode.java

java 复制代码
package com.example.recycler;

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

// TreeNode.java
public class TreeNode {
    private String id;
    private String name;
    private int level; // 层级,0开始
    private boolean isExpanded; // 是否展开
    private TreeNode parent; // 父节点
    private List<TreeNode> children; // 子节点
    private Object data; // 其他数据

    public TreeNode(String id, String name,int level) {
        this.id = id;
        this.name = name;
        this.children = new ArrayList<>();
        this.isExpanded = false;
        this.level = level;
    }

    // Getters and Setters
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

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

    public int getLevel() { return level; }
    public void setLevel(int level) { this.level = level; }

    public boolean isExpanded() { return isExpanded; }
    public void setExpanded(boolean expanded) { isExpanded = expanded; }

    public TreeNode getParent() { return parent; }
    public void setParent(TreeNode parent) { this.parent = parent; }

    public List<TreeNode> getChildren() { return children; }
    public void setChildren(List<TreeNode> children) { this.children = children; }

    public Object getData() { return data; }
    public void setData(Object data) { this.data = data; }

    // 添加子节点
    public void addChild(TreeNode child) {
        child.setParent(this);
        child.setLevel(this.level + 1);
        children.add(child);
    }

    // 判断是否有子节点
    public boolean hasChildren() {
        return children != null && !children.isEmpty();
    }
}

MultiLevelAdapter.java

java 复制代码
package com.example.recycler;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

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

public class MultiLevelAdapter extends RecyclerView.Adapter<MultiLevelAdapter.ViewHolder> {

    private List<TreeNode> displayNodes; // 实际显示的数据
    private List<TreeNode> allNodes; // 所有数据
    private OnItemClickListener listener;

    public MultiLevelAdapter(List<TreeNode> data) {
        this.allNodes = data;
        this.displayNodes = getDisplayNodes(data);
    }

    // 获取要显示的节点(展开的节点)
    private List<TreeNode> getDisplayNodes(List<TreeNode> nodes) {
        List<TreeNode> result = new ArrayList<>();
        for (TreeNode node : nodes) {
            result.add(node);
            if (node.isExpanded() && node.hasChildren()) {
                result.addAll(getDisplayNodes(node.getChildren()));
            }
        }
        return result;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_multi_level, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
        TreeNode node = displayNodes.get(position);

        // 设置缩进
        int paddingLeft = node.getLevel() * 50; // 每级缩进50dp
        System.out.println("缩进:::"+paddingLeft);
        holder.itemView.setPadding(paddingLeft, 0, 0, 0);

        // 设置文本
        holder.textView.setText(node.getName());

        // 设置箭头图标
        if (node.hasChildren()) {
            holder.arrowIcon.setVisibility(View.VISIBLE);
        } else {
            holder.arrowIcon.setVisibility(View.GONE);
        }
		if (node.isExpanded())
			//展开图片设置
			holder.arrowIcon.setBackground(你的图片)
		else
			//收起图片设置
			holder.arrowIcon.setBackground(你的图片)
        // 点击事件
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int adapterPosition = holder.getAdapterPosition();
                if (adapterPosition != RecyclerView.NO_POSITION) {
                    TreeNode clickedNode = displayNodes.get(adapterPosition);
                    if (clickedNode.hasChildren()) {
                        // 有子节点:切换展开/收起状态
                        int removeCount = 0;
                        if (clickedNode.isExpanded()) {
                            removeCount = countAllChildren(clickedNode);
                            clearAllChildExpand(clickedNode);
                        }
                        clickedNode.setExpanded(!clickedNode.isExpanded());
                        refreshDisplayNodes();
						//int a = 收起图片
                        if (clickedNode.isExpanded()) {
							a = 展开图片
                            notifyItemRangeInserted(adapterPosition + 1, clickedNode.getChildren().size());
                        }else if (!clickedNode.isExpanded()&&removeCount!=0){
                            notifyItemRangeRemoved(adapterPosition + 1, removeCount);
                        }
						holder.arrowIcon.setBackground(a)

                    } else {
                        // 没有子节点:触发点击事件
                        if (listener != null) {
                            listener.onItemClick(clickedNode);
                        }
                    }
                }
            }
        });

        // 长按事件(可选)
        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (listener != null) {
                    return listener.onItemLongClick(displayNodes.get(holder.getAdapterPosition()));
                }
                return false;
            }
        });
    }

    // 计算节点的所有子节点数量(包括子节点的子节点)
    private int countAllChildren(TreeNode node) {
        int count = 0;
        if (node.hasChildren() && node.isExpanded()) {
            for (TreeNode child : node.getChildren()) {
                count++;
                if (child.isExpanded()) {
                    count += countAllChildren(child);
                }
            }
        }
        return count;
    }
    private void clearAllChildExpand(TreeNode node) {
        if (node.hasChildren()) {
            for (TreeNode child : node.getChildren()) {
                child.setExpanded(false);
                clearAllChildExpand(child);
            }
        }
    }

    // 刷新显示的数据
    private void refreshDisplayNodes() {
        displayNodes = getDisplayNodes(allNodes);
    }

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

    // 设置数据
    public void setData(List<TreeNode> data) {
        this.allNodes = data;
        refreshDisplayNodes();
        notifyDataSetChanged();
    }

    // 展开/收起所有节点
    public void expandAll() {
        setExpandedForAll(allNodes, true);
        refreshDisplayNodes();
        notifyDataSetChanged();
    }

    public void collapseAll() {
        setExpandedForAll(allNodes, false);
        refreshDisplayNodes();
        notifyDataSetChanged();
    }

    private void setExpandedForAll(List<TreeNode> nodes, boolean expanded) {
        for (TreeNode node : nodes) {
            node.setExpanded(expanded);
            if (node.hasChildren()) {
                setExpandedForAll(node.getChildren(), expanded);
            }
        }
    }

    // ViewHolder
    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView textView;
        ImageView arrowIcon;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.tv_item_name);
            arrowIcon = itemView.findViewById(R.id.iv_arrow);
        }
    }

    // 点击监听接口
    public interface OnItemClickListener {
        void onItemClick(TreeNode node);
        boolean onItemLongClick(TreeNode node);
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }
}

MainActivity.java

java 复制代码
package com.example.recycler;


import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.widget.Toast;

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

// MainActivity.java
public class MainActivity extends Activity {

    private RecyclerView recyclerView;
    private MultiLevelAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        // 创建测试数据
        List<TreeNode> data = createTestData();

        adapter = new MultiLevelAdapter(data);
        recyclerView.setAdapter(adapter);

        // 设置点击监听
        adapter.setOnItemClickListener(new MultiLevelAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(TreeNode node) {
                // 处理没有子节点的点击事件
                Toast.makeText(MainActivity.this,
                        "点击了: " + node.getName(), Toast.LENGTH_SHORT).show();

                // 可以在这里处理业务逻辑
                handleLeafClick(node);
            }

            @Override
            public boolean onItemLongClick(TreeNode node) {
                // 长按事件
                showOptionsDialog(node);
                return true;
            }
        });
    }

    // 创建测试数据(支持无限层级)
    private List<TreeNode> createTestData() {
        List<TreeNode> rootNodes = new ArrayList<>();

        // 第1级
        for (int i = 1; i <= 3; i++) {
            TreeNode level1 = new TreeNode("1-" + i, "一级节点 " + i,0);
            level1.setLevel(0);

            // 第2级
            for (int j = 1; j <= 2; j++) {
                TreeNode level2 = new TreeNode("2-" + i + "-" + j, "二级节点 " + i + "-" + j,level1.getLevel());
                level1.addChild(level2);

                // 第3级
                for (int k = 1; k <= (i == 1 ? 3 : 0); k++) {
                    TreeNode level3 = new TreeNode("3-" + i + "-" + j + "-" + k,
                            "三级节点 " + i + "-" + j + "-" + k,level2.getLevel());
                    level2.addChild(level3);

                    // 第4级(演示无限层级)
                    if (i == 1 && j == 1) {
                        for (int l = 1; l <= 2; l++) {
                            TreeNode level4 = new TreeNode("4-" + i + "-" + j + "-" + k + "-" + l,
                                    "四级节点 " + i + "-" + j + "-" + k + "-" + l,level3.getLevel());
                            level3.addChild(level4);
                        }
                    }
                }
            }

            rootNodes.add(level1);
        }

        return rootNodes;
    }

    // 处理叶子节点点击
    private void handleLeafClick(TreeNode node) {
        // 这里实现你的业务逻辑
        Log.d("MultiLevel", "点击了叶子节点: " + node.getName());
    }
}
相关推荐
青风行2 小时前
Android从入门到进阶
android
方白羽2 小时前
Android 开发中,准确判断应用处于“前台(Foreground)”还是“后台(Background)
android·app·客户端
Mart!nHu3 小时前
Android 10&15 Framework 允许设置系统时间早于编译时间
android
编程之路从0到14 小时前
ReactNative新架构之Android端TurboModule机制完全解析
android·react native·源码阅读
iloveAnd5 小时前
Android开发中痛点解决(二)兼容性:AndroidX和gradle版本的兼容性
android·兼容性·androidx
stevenzqzq5 小时前
DataStore基本使用教程
android
LawrenceMssss6 小时前
由于创建一个完整的App涉及到多个层面(如前端、后端、数据库等),并且每种语言通常有其特定的用途(如Java/Kotlin用于Android开发,Swift/Objective-C用于iOS开发,Py
android·java·ios
chen_mangoo7 小时前
HDMI简介
android·linux·驱动开发·单片机·嵌入式硬件
阿里-于怀7 小时前
AgentScope AutoContextMemory:告别 Agent 上下文焦虑
android·java·数据库·agentscope