能伸能缩的ExpandableListView(仿智联招聘专业选择列表页面)

本文主要是介绍能伸能缩的ExpandableListView(仿智联招聘专业选择列表页面),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、前言

前些日子项目中需要实现一个类似于智联招聘的专业选择页面,简单地说就是点击一级专业列表中的某一项就会展开二级专业列表,一级列表就是一个个组(组选项),二级列表就是一个组里面的成员(子选项)。智联招聘的效果如下:

智联招聘-未展开样式

智联招聘-展开子列表

现在的主流列表控件毫无疑问是RecyclerView,所以你也许会想到用一个RecyclerView来显示组列表,然后在其item里面再嵌套一个RecyclerView显示子选项列表。点击组选项就将嵌套的RecyclerView布局设为visible或者gone来展开和关闭子列表。这种做法有如下的缺点:

  1. RecyclerView的嵌套容易造成卡顿;
  2. 点击组列表的最后一项时,虽然子列表已经显示了,但是在屏幕之外,需要向上滑动才能看到,用户体验不是很好。

虽然RecyclerView是当红炸子鸡,但是解决这些问题还是得老司机ExpandableListView出马了。这是有点年头的控件了,不过宝刀未老,我们可以用它轻松实现下拉列表效果。在这里我不打算一一罗列ExpandableListView的用法,而是采取实战的方式,以实现需求为中心,用到哪个再讲那个。因为我觉得在实战中学习和填坑更有趣味,更有效果。所以,下面我们就一起来做一个智联招聘的专业选择页面吧。

先提前看看我们要实现的效果:

专业列表选择页效果图

二、布局

2.1 主布局

整体布局很简单,放一个ExpandableListView就可以了:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><ExpandableListView
        android:id="@+id/expandable_list"android:layout_width="match_parent"android:layout_height="match_parent" /></FrameLayout>

2.2 组选项的item布局

组选项只需要显示文字,所以先放一个TextView:

<?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"android:layout_width="match_parent"android:layout_height="50dp"android:paddingLeft="20dp"android:gravity="center_vertical"android:background="@android:color/white"android:orientation="vertical"><TextView
        android:text="dd"android:gravity="center_vertical"android:id="@+id/tv_group"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="@android:color/black"android:textSize="16sp" /></LinearLayout>

2.3 子选项的item布局

子选项的item布局与组选项的唯一区别就是它的背景是灰色的(android:background="#F2F2F2"),代码就不重复贴了。

三、数据准备

一个组选项对应的是一组子选项,所以组选项的数据是一个一级数组,子选项的数据是二级数组。为了添加数据方便,我这里使用的是集合,每一组的子选项数据个数设为随机:

    private void initData(){//初始化一级专业数据for (int i = 1; i <= 15; i++) {groupList.add(new StringBuffer("一级专业").append(i).toString());}//初始化二级专业数据Random random = new Random();for (String s : groupList) {List<String> childDatas = new ArrayList<>();int size = random.nextInt(10) + 5;for (int i = 1; i <= size; i++) {childDatas.add(new StringBuffer("二级专业").append(i).toString());}childList.add(childDatas);}}

运行之后发现数据都有了,但是见鬼,为什么组选项和子选项的高度都那么窄呢?

四、选项高度为wrap_content的坑

这可以算是ExpandableListView的一个小坑,当组选项或者子选项的根布局高度设置为固定值,实际出来的效果却是wrap_content。解决这个问题可以给根布局再加一个属性android:minHeight="50dp",或者也给子控件TextView加上固定的高度(如果你的item里面的控件比较简单可以采取这个方法)。当然,如果你的item高度不是一个固定值,也可以将高度设为wrap_content,然后在里面设置padding或者margin值,比如:

        android:paddingTop="10dp"android:paddingBottom="10dp"

你可以根据需求采取合适的方案。

五、修改组选项的指示器

仔细观察我们可以发现,ExpandableListView默认显示了一个指示器,也就是左边的小箭头,并且提供了属性android:groupIndicator来设置其样式。这个指示器是固定在左边的,虽然可以设置上下左右的距离,但是很难控制,一不小心就会跟文字重叠,所以我做法是干脆设置android:groupIndicator="@null"让其消失,然后自己在组选项的布局中用两张图片来替代。

组选项的布局修改如下:

<?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"android:layout_width="match_parent"android:layout_height="50dp"android:background="@android:color/white"android:gravity="center_vertical"android:minHeight="50dp"android:orientation="vertical"android:paddingLeft="20dp"><RelativeLayout
        android:layout_width="match_parent"android:layout_height="wrap_content"><TextView
            android:layout_toLeftOf="@+id/iv_indicator"android:layout_centerVertical="true"android:id="@+id/tv_group"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_vertical"android:textColor="@android:color/black"android:textSize="16sp" /><ImageView
            android:layout_marginRight="20dp"android:id="@+id/iv_indicator"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:layout_width="wrap_content"android:layout_height="wrap_content" /></RelativeLayout>
</LinearLayout>

回到MajorAdapter,在getGroupView方法中有一个isExpanded参数,它表示的是组选项的展开状态,true时表示展开,false则是闭合。有了它,我们就可以轻松决定箭头指示器的方向了。

    @Overridepublic View getGroupView(int groupPosition, boolean isExpanded,View convertView, ViewGroup parent) {……//根据列表的展开状态来决定箭头的方向groupHolder.ivIndicator.setImageResource(isExpanded ?R.drawable.ic_arrow_up : R.drawable.ic_arrow_down);return convertView;}

六、修改分割线样式

ExpandableListView是继承于ListView,所以它也可以通过android:divider属性来同时设置组选项和子选项的分割线。我们需要的分割线左边有20dp的间距,所以只好设置android:divider="@null"来去掉原生的分割线,并且自己写一条了。

创建一个layout_divider.xml的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:background="#d4d4d4"android:layout_height="0.5dp">
</RelativeLayout>

然后在组选项和子选项的布局中include进去:

<include layout="@layout/layout_divider" />

至此,我们的界面就已经完成了,现在来实现它的点击事件吧。

七、组选项和子选项的点击事件

ExpandableListView提供了setOnGroupClickListenersetOnChildClickListener两个方法来分别监听组选项和子选项的点击事件。比如监听子选项的点击事件:

        //子选项的点击事件expandableList.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {@Overridepublic boolean onChildClick(ExpandableListView parent, View v, int groupPosition,int childPosition, long id) {String toastStr = new StringBuffer("你选择了").append(groupList.get(groupPosition)).append("的").append(childList.get(groupPosition).get(childPosition)).toString();Toast.makeText(context, toastStr, Toast.LENGTH_SHORT).show();return false;}});

组选项的点击监听事件相似,这里就不再赘述了。

八、组选项的展开监听事件

现在我们来实现一个智联招聘中没有的功能吧,即点击某一组选项时,被点击的组选项展开,其他展开的组选项自动关闭,也就是每次只能有一个组选项展开子列表。你也许会想到用上一节中的setOnGroupClickListener,但是这个是每次组选项被点击时都会监听,哪怕是一件关闭了,所以性能上会有点浪费。除此之外,我们还有更好的选择,那就是使用setOnGroupExpandListener监听列表的展开事件:

        //实现每次只展开一个组选项列表的功能expandableList.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {@Overridepublic void onGroupExpand(int groupPosition) {//获取组选项个数int groupSize = expandableList.getExpandableListAdapter().getGroupCount();for (int i = 0; i < groupSize; i++) {if (i != groupPosition && expandableList.isGroupExpanded(i)) {//不是当前点击的组选项且处于展开状态的就关闭expandableList.collapseGroup(i);}}}});

每次点击展开某个组选项时,我们就遍历组选项列表,比较它们的groupPosition,如果不是当前点击的组选项且处于展开状态,就调用collapseGroup将其关闭。

你一定会想到,既然有方法可以将某一组选项里面的列表关闭,是不是也有对应的方法展开呢?没错,相对于collapseGroup,还有对应的expandGroup方法,而且它的第二个参数可以设置展开时是否显示动画效果。如果你想页面显示时就展开某一特定的子列表,那么就可以使用expandGroup了。

九、总结

至此,我们的界面和功能都已经实现完毕了。现在就来梳理用到的属性和API吧。

首先是xml属性:

属性作用
android:groupIndicator设置组选项的指示器
android:divider设置组选项和子选项列表的分割线

然后是用到的方法:

方法作用
setOnGroupExpandListener组选项的点击监听事件
setOnChildClickListener子选项的点击监听事件
setOnGroupExpandListener组选项的展开监听事件
getExpandableListAdapter获取ExpandableListView绑定的Adapter
collapseGroup关闭某一组选项下的列表
expandGroup展开某一组选项下的列表

如果你还想深入学习ExpandableListView,可以阅读这份官方文档:
http://www.android-doc.com/reference/android/widget/ExpandableListView.html#getFlatListPosition(long)

十、源码提供

源码我放做了码云上,但是由于里面还有我的一些乱七八糟的代码,所以不建议大家把整个工程下载下来,只需关注ExpandableListView包下面这几个文件就行了:

  • ExpandableListViewActivity
  • MajorFragment
  • MajorAdapter

我也将本项目的代码和资源文件打包上传到了百度网盘,你可以直接下载使用:百度网盘

事实上,这里代码难度不大,所以我强烈建议你亲自动手敲一遍。最后,祝大家学习愉快。

这篇关于能伸能缩的ExpandableListView(仿智联招聘专业选择列表页面)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/234035

相关文章

如何选择适合孤独症兄妹的学校?

在探索适合孤独症儿童教育的道路上,每一位家长都面临着前所未有的挑战与抉择。当这份责任落在拥有孤独症兄妹的家庭肩上时,选择一所能够同时满足两个孩子特殊需求的学校,更显得尤为关键。本文将探讨如何为这样的家庭做出明智的选择,并介绍星贝育园自闭症儿童寄宿制学校作为一个值得考虑的选项。 理解孤独症儿童的独特性 孤独症,这一复杂的神经发育障碍,影响着儿童的社交互动、沟通能力以及行为模式。对于拥有孤独症兄

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

c++的初始化列表与const成员

初始化列表与const成员 const成员 使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。 不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。 在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。 初始化列表 在构造函数小括号后面,主要用于给

如何选择SDR无线图传方案

在开源软件定义无线电(SDR)领域,有几个项目提供了无线图传的解决方案。以下是一些开源SDR无线图传方案: 1. **OpenHD**:这是一个远程高清数字图像传输的开源解决方案,它使用SDR技术来实现高清视频的无线传输。OpenHD项目提供了一个完整的工具链,包括发射器和接收器的硬件设计以及相应的软件。 2. **USRP(Universal Software Radio Periphera

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

Spring+MyBatis+jeasyui 功能树列表

java代码@EnablePaging@RequestMapping(value = "/queryFunctionList.html")@ResponseBodypublic Map<String, Object> queryFunctionList() {String parentId = "";List<FunctionDisplay> tables = query(parent

为什么现在很多人愿意选择做债务重组?债重组真的就这么好吗?

债务重组,起初作为面向优质企业客户的定制化大额融资策略,以其高效周期著称,一个月便显成效。然而,随着时代的车轮滚滚向前,它已悄然转变为负债累累、深陷网贷泥潭者的救赎之道。在此路径下,个人可先借助专业机构暂代月供,经一段时间养护征信之后,转向银行获取低成本贷款,用以替换高昂网贷,实现利息减负与成本优化的双重目标。 尽管债务重组的代价不菲,远超传统贷款成本,但其吸引力依旧强劲,背后逻辑深刻。其一