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 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台2 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone2 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc2 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo2 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077002 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼2 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone2 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen2 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone2 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui