Android中的二级列表-ExpandableListView

news2025/1/20 15:38:48

Android中的二级下拉列表,类似于某Q的分组,采用ExpandableListView实现,适配器方法如下。

先看效果图:有四个分组,每个分组下都有一些子条目,可以跟着父条目展开而显示

 实现代码:

一级列表是一个ArrayList,二级列表是一个HashMap。

    <ExpandableListView
        android:id="@+id/expandableListView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:nestedScrollingEnabled="false"
        android:layout_weight="1"/>
     //添加一级数据项 存储一级菜单的名字
        ArrayList<String> firstLevelMenuList = SeatModelManager.getInstance().getTxGroups();

        //二级数据
        LinkedHashMap<String, List<String>> secondItems = new LinkedHashMap<>();
        ArrayList<String> txNameList;

        for (int i = 0; i < firstLevelMenuList.size(); i++) {
            ArrayList<Tx> txes = SeatModelManager.getInstance().readTxByGroup(firstLevelMenuList.get(i));
            txNameList = new ArrayList<>();
            for (int j = 0; j < txes.size(); j++) {
               //根据一级菜单的名字匹配自己所在的父条目
                if (txes.get(j).getGroup().equals(firstLevelMenuList.get(i))) {
                    txNameList.add(txes.get(j).getTxName());
                }
            }
            secondItems.put(firstLevelMenuList.get(i), txNameList);
        }

        expandableListView = inflate.findViewById(R.id.expandableListView);
        expandableListAdapter = new ExpandableListviewAdapter(getActivity(), firstLevelMenuList, secondItems);
        expandableListView.setAdapter(expandableListAdapter);

适配器,构造方法里的代码根据需要进行编写

public class ExpandableListviewAdapter extends BaseExpandableListAdapter {
    private static final String TAG = "ExpandableListviewAdapt";

    private ArrayList<String> firstItems;
    private Map<String, List<String>> secondItems;
    private Map<String, boolean[]> secondItemSelection;//记录子条目选中状态

    private List<String> selectChildItems;//记录子条目的顺序

    public ExpandableListviewAdapter(Context context, ArrayList<String> firstItems, Map<String, List<String>> secondItems) {
        this.context = context;
        this.firstItems = firstItems;
        this.secondItems = secondItems;
        secondItemSelection = new HashMap<>();
        selectChildItems = new ArrayList<>();//初始化子条目中的顺序列表
        //初始化子条目的选中状态
        for (String first : firstItems) {
            int secondCunt = secondItems.get(first).size();
            boolean[] selection = new boolean[secondCunt];
            secondItemSelection.put(first, selection);
        }
    }

    //返回当前被选中的子条目的数据
    public ArrayList<String> getSelectChildItems() {
        ArrayList<String> selectItems = new ArrayList<>();
        for (String firstItem : firstItems) {
            boolean[] selection = secondItemSelection.get(firstItem);
            List<String> second = secondItems.get(firstItem);
            for (int i = 0; i < selection.length; i++) {
                if (selection[i]) {
                    selectItems.add(second.get(i));
                }
            }
        }
        //创建新的列表 按照顺序添加子条目
        ArrayList<String> selectItemsInOrder = new ArrayList<>();
        for (String item : selectChildItems) {
            if (selectItems.contains(item)) {
                selectItemsInOrder.add(item);
            }
        }
        return selectItemsInOrder;
    }


    @Override
    public int getGroupCount() {
        return firstItems.size();
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        String s = firstItems.get(groupPosition);
        List<String> strings = secondItems.get(s);
        return strings != null ? strings.size() : 0;
    }

    @Override
    public Object getGroup(int groupPosition) {
        return firstItems.get(groupPosition);
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return secondItems.get(groupPosition);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        GroupViewHolder groupViewHolder;
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.item_parent, null);
            groupViewHolder = new GroupViewHolder();
            groupViewHolder.parentTv = convertView.findViewById(R.id.item_parent_tv);
            groupViewHolder.parentTv.setText(firstItems.get(groupPosition));
            convertView.setTag(groupViewHolder);
        }
        return convertView;
    }

    TextView childNum;

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {

        if (convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            convertView = inflater.inflate(R.layout.item_child, parent, false);
        }

        //设置子布局
        String firstItem = firstItems.get(groupPosition);
        boolean[] selection = secondItemSelection.get(firstItem);
        boolean isSelect = selection[childPosition];
        String secondItem = secondItems.get(firstItem).get(childPosition);

        TextView childText = convertView.findViewById(R.id.item_child_tv);
        CheckBox childCb = convertView.findViewById(R.id.item_child_cb);
        childNum = convertView.findViewById(R.id.item_num);

        childText.setText(secondItem);
        childCb.setChecked(isSelect);

        //获取当前子条目在列表中的位置
        int index = getChildIndex(groupPosition, childPosition);
        if (index > 0) {
            childNum.setText(String.valueOf(index));//设置数字角标
            childNum.setVisibility(View.VISIBLE);
            childCb.setChecked(true);
        } else {
            childNum.setVisibility(View.INVISIBLE);
            childCb.setChecked(false);
        }


        //复选框的监听事件
        childCb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                boolean isChecked = childCb.isChecked();
                selection[childPosition] = isChecked;
                //处理选中的状态逻辑
                if (isChecked) {
                    String childItem = secondItems.get(firstItem).get(childPosition);
                    selectChildItems.add(childItem);

                } else {
                    //子条目取消选中 移除选中的子条目
                    String childItem = secondItems.get(firstItem).get(childPosition);
                    selectChildItems.remove(childItem);
                }
                notifyDataSetChanged();
                List<String> selectChildItems = getSelectChildItems();
                Log.d(TAG, "getGroupView: " + selectChildItems);
            }
        });


        return convertView;
    }

    /**
     * 获取子条目在列表中的位置
     *
     * @param groupPosition
     * @param childPosition
     * @return
     */
    private int getChildIndex(int groupPosition, int childPosition) {
        String firstItem = firstItems.get(groupPosition);
        String secondItem = secondItems.get(firstItem).get(childPosition);
        int index = selectChildItems.indexOf(secondItem);
        // 由于索引从0开始,所以需要加1
        return index + 1;
    }


    public void setSelectChildItems(ArrayList<String> selectChildItems) {
        this.selectChildItems = selectChildItems;
//        for (int i = 0; i < selectChildItems.size(); i++) {
//            String s = selectChildItems.get(i);
//            for (String second : selectChildItems)
//                if (s.equals(second)) {
//
//                }
//        }
        notifyDataSetChanged();//更新页面显示
    }

    //指定位置上的子元素是否可选中
    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }

    //刷新子条目数据
    public void updateChildData(int groupPosition, List<String> childList) {
        notifyDataSetChanged();
    }

    public void updateChildView() {
        notifyDataSetChanged();
    }

    static class GroupViewHolder {
        TextView parentTv;
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/884029.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于STM32的超声波雷达

视频地址:1.基于STM32的超声波雷达-演示_哔哩哔哩_bilibili 备注:文档最后有所有文件的网盘地址 1. 项目展示 1.1. 最终效果 1.2. 项目硬件 全部必要硬件(左到右): ST-LINK调试器:调试下载程序stm32f103c8t6核心板1.8寸TFT显示器sg90舵机超声波传感器

题解 | #1002.Shortest path# 2023杭电暑期多校9

1002.Shortest path 签到题 记忆化搜索 题目大意 给定一个正整数 n n n &#xff0c;可以对其进行以下操作&#xff1a; 如果 n n n 能被 3 3 3 整除&#xff0c;则可以使 n n / 3 nn/3 nn/3 ;如果 n n n 能被 2 2 2 整除&#xff0c;则可以使 n n / 2 nn/2 nn/2 …

JavaScript(JavaEE初阶系列13)

目录 前言&#xff1a; 1.初识JavaScript 2.JavaScript的书写形式 2.1行内式 2.2内嵌式 2.3外部式 2.4注释 2.5输入输出 3.语法 3.1变量的使用 3.2基本数据类型 3.3运算符 3.4条件语句 3.5循环语句 3.6数组 3.7函数 3.8对象 3.8.1 对象的创建 4.案例演示 4…

【MyBatis】查询数据库

目录 一、什么是MyBatis 二、MyBatis框架的搭建 1、搭建MyBatis框架 2、设置MyBaits项目的配置 三、使用MyBatis完成数据库的操作 1、MyBatis程序中sql语句的即时执行和预编译 1.1、即时执行&#xff08;${}&#xff09; 1.2、预编译&#xff08;#{}&#xff09; 1.3、即…

多态原理解析

一 多态应用 首先&#xff0c;什么是多态呢?很多概念起初我们都是不理解的&#xff0c;就像我们刚接触继承一样&#xff0c;当学完后发现其实也没那么难&#xff0c;也挺容易理解的。 多态详细点就是多种状态&#xff0c;例如游戏中的抽宝箱&#xff0c;每个人难道都是一样的…

6.文件实现

第四章 文件管理 6.文件实现 ​   连续分配方式&#xff1a;逻辑上相邻的块在物理上也必须相邻&#xff0c;也必须是占有一组连续的块并且依然需要保持这些块之间的相对顺序。 在连续分配方式下为了实现逻辑块号到物理块号之间的映射关系&#xff0c;在文件的目录表中必须记…

JAVA语言:什么是懒加载机制?

JVM没有规定什么时候加载,一般是什么时候使用这个class才会什么时候加载,但是JVM规定了什么时候必须初始化(初始化是第三步、装载、连接、初始化),只要加载之后,那么肯定是要进行初始化的,所以我们就可以通过查看这个类有没有进行初始化,从而判断这个类有没有被加载。 …

文件批量重命名怎么去括号?

文件批量重命名怎么去括号&#xff1f;平时我们一个一个修改文件名称的时候&#xff0c;是不会有括号的。但如果你使用传统的方法来进行文件批量重命名&#xff0c;那么最后得到的文件名是这样的“音频 (数字编号)”&#xff0c;这些文件的名称中会包含一个中文括号。这这个括号…

8.15起 webserver笔记

XShell 远程连接 XFTP 文件传输 VSC远程连接虚拟机&#xff0c;vim编辑器用起来不方便&#xff1a; 查看虚拟机IP地址&#xff1a; MY&#xff1a; 192.168.42.138 VSC每次都要密码&#xff0c;配置免密登录&#xff1a; 在本机命令行生成用户私钥&#xff1a;

JDBC连接数据库(mysql)

准备jar包 官网下载即可&#xff0c;这里提供两个我下载过的jar包&#xff0c;供使用 链接&#xff1a;https://pan.baidu.com/s/1snikBD1kEBaaJnVktLvMdQ?pwdrwwq 提取码&#xff1a;rwwq eclipse导 jar包: 导入成功会有如下所示&#xff1a; ---------------------------…

LeetCode ACM模式——二叉树篇(二)

刷题顺序及思路来源于代码随想录&#xff0c;网站地址&#xff1a;https://programmercarl.com 二叉树的定义及创建见&#xff1a; LeetCode ACM模式——二叉树篇&#xff08;一&#xff09;_要向着光的博客-CSDN博客 目录 102. 二叉树的层序遍历 利用队列 利用递归 10…

sql类型-用户定义表类型

一、创建用户定义表类型String_Table_Type CREATE TYPE String_Table_Type AS TABLE ( Id nvarchar(200) NOT NULL ) GO DECLARE test String_Table_Type INSERT INTO test VALUES(a),(b),(c) SELECT * FROM test 二、SqlSugar中使用

VBA manual

VBA MACRO 修复乱码打开VBAAlt F11File/Options/Customize Ribbon 修复乱码 Tools / Options Control Pannel / Region 打开VBA Alt F11 快速打开VBA File/Options/Customize Ribbon

融云:以对话为场景本质,AIGC 将如何改变游戏规则

8 月 17 日&#xff08;本周四&#xff09;&#xff0c;融云直播课从排查问题到预警风险&#xff0c;社交产品如何更好保障体验、留住用户&#xff1f;欢迎点击报名~ 生成式 AI 公司 MosaicML 以约 13 亿美元的价格被大数据巨头 Databricks 收购&#xff0c;这个发生于 6 月底的…

了解51单片机

目录 51单片机名字的由来 主要功能 1.控制处理 2.数据处理 3.通信 4.定时计数 51单片机的组成 1.中央处理器CPU 2.存储器RAM、只读存储器ROM 3.I/O口和中断系统 4.显示驱动电路、A/D转换器 5.定时器/计数器、脉宽调制电路、模拟多路转换器等电路 单片机的应用领域(…

“探索超前的Pinia:解密Vue.js最新热门状态管理库“

在Vue.js开发者的世界中&#xff0c;一个令人兴奋的新宠儿已经崭露头角&#xff0c;它就是Pinia。对于那些在状态管理方面追求卓越的人来说&#xff0c;Pinia是一片沃土&#xff0c;可以帮助你构建出令人叹为观止的应用程序。无论你是一名有经验的开发者&#xff0c;还是刚入门…

《开放加速规范AI服务器设计指南》发布,应对生成式AI爆发算力挑战

8月10日&#xff0c;在2023年开放计算社区中国峰会(OCP China Day 2023)上&#xff0c;《开放加速规范AI服务器设计指南》&#xff08;以下简称《指南》&#xff09;发布。《指南》面向生成式AI应用场景&#xff0c;进一步发展和完善了开放加速规范AI服务器的设计理论和设计方法…

小白到运维工程师自学之路 第七十五集 (Kubernetes 企业级高可用部署)2

8、添加master节点 在k8s-master2和k8s-master3节点创建文件夹 mkdir -p /etc/kubernetes/pki/etcd在k8s-master1节点执行 从k8s-master1复制密钥和相关文件到k8s-master2和k8s-master3 scp /etc/kubernetes/admin.conf root192.168.77.15:/etc/kubernetes scp /etc/kubernet…

TPAMI, 2023 | 用压缩隐逆向神经网络进行高精度稀疏雷达成像

CoIR: Compressive Implicit Radar | IEEE TPAMI, 2023 | 用压缩隐逆向神经网络进行高精度稀疏雷达成像 注1:本文系“无线感知论文速递”系列之一,致力于简洁清晰完整地介绍、解读无线感知领域最新的顶会/顶刊论文(包括但不限于Nature/Science及其子刊;MobiCom, Sigcom, MobiSy…

〔011〕Stable Diffusion 之 解决绘制多人或面部很小的人物时面部崩坏问题 篇

✨ 目录 &#x1f388; 脸部崩坏&#x1f388; 下载脸部修复插件&#x1f388; 启用脸部修复插件&#x1f388; 插件生成效果&#x1f388; 插件功能详解 &#x1f388; 脸部崩坏 相信很多人在画图时候&#xff0c;特别是画 有多个人物 图片或者 人物在图片中很小 的时候&…