前言

  在需要实现一个List的item需要包含列表的时候,我们就可以选择ExpandableListView. 其实这个View的原始设计还是ListView的那套.就是增加2层的ListView而已.所以在写它的适配器与ListView的适配器挺相似的,所以会有一个通病就是没有Item的View的复用机制请一定要注意这点,在实现使用的时候需要写Item的View的复用,减少内存与增加性能.

一个简单的Demo

  老规矩,先来一个最简单的demo来了解下最基本的使用方法.注意!这个demo是没有在Adapter写任何View复用机制的请不要用到实际项目中. demo只是帮助你快速认识了解ExpandableListView

效果图

  

Activity的Xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="vertical"
tools:context=".MainActivity"> <ExpandableListView
android:id="@+id/expandablelistview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ExpandableListView> </LinearLayout>

一级Item和二级Item用的xml布局

偷懒,我让一级和二级都使用一个布局

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="45dp"
android:text="内容"
android:textSize="15sp"
android:textColor="@color/fontBlack3"
android:gravity="center"
android:background="@color/colorWhite">
</TextView>

编写适配器

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
import java.util.List; public class DemoAdapter extends BaseExpandableListAdapter {
List<String> mGroupList;//一级List
List<List<String>> mChildList;//二级List 注意!这里是List里面套了一个List<String>,实际项目你可以写一个pojo类来管理2层数据 public DemoAdapter(List<String> groupList, List<List<String>> childList){
mGroupList = groupList;
mChildList = childList; } @Override
public int getGroupCount() {//返回第一级List长度
return mGroupList.size();
} @Override
public int getChildrenCount(int groupPosition) {//返回指定groupPosition的第二级List长度
return mChildList.get(groupPosition).size();
} @Override
public Object getGroup(int groupPosition) {//返回一级List里的内容
return mGroupList.get(groupPosition);
} @Override
public Object getChild(int groupPosition, int childPosition) {//返回二级List的内容
return mChildList.get(groupPosition).get(childPosition);
} @Override
public long getGroupId(int groupPosition) {//返回一级View的id 保证id唯一
return groupPosition;
} @Override
public long getChildId(int groupPosition, int childPosition) {//返回二级View的id 保证id唯一
return groupPosition + childPosition;
} /**
* 指示在对基础数据进行更改时子ID和组ID是否稳定
* @return
*/
@Override
public boolean hasStableIds() {
return true;
} /**
* 返回一级父View
*/
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_item, parent,false);
((TextView)convertView).setText((String)getGroup(groupPosition));
return convertView;
} /**
* 返回二级子View
*/
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_item, parent,false);
((TextView)convertView).setText((String)getChild(groupPosition,childPosition));
return convertView;
} /**
* 指定位置的子项是否可选
*/
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}

Activity里的代码

        mExpandableListView = findViewById(R.id.expandablelistview);

        List<String> groupList = new ArrayList<>();
groupList.add("一");
groupList.add("二");
groupList.add("三"); List<List<String>> childList = new ArrayList<>();
List<String> childList1 = new ArrayList<>();
childList1.add("1");
childList1.add("1");
childList1.add("1");
List<String> childList2 = new ArrayList<>();
childList2.add("2");
childList2.add("2");
childList2.add("2");
List<String> childList3 = new ArrayList<>();
childList3.add("3");
childList3.add("3");
childList3.add("3"); childList.add(childList1);
childList.add(childList2);
childList.add(childList3); DemoAdapter demoAdapter = new DemoAdapter(groupList, childList);
mExpandableListView.setAdapter(demoAdapter); mExpandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {//一级点击监听
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { //如果你处理了并且消费了点击返回true,这是一个基本的防止onTouch事件向下或者向上传递的返回机制
return false;
}
}); mExpandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {//二级点击监听
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { //如果你处理了并且消费了点击返回true
return false;
}
});

其他Xml属性

android:dividerHeight="20dp" 设置item间距高度,注意设置这个间距包括了一级和二级

android:divider="@color/colorRed1" 设置一级间距颜色

android:childDivider="@color/colorGreen" 设置二级间距颜色

android:childIndicator:显示在子列表旁边的Drawable对象,可以是一个图像

android:childIndicatorEnd:子列表项指示符的结束约束位置

android:childIndicatorLeft:子列表项指示符的左边约束位置

android:childIndicatorRight:子列表项指示符的右边约束位置

android:childIndicatorStart:子列表项指示符的开始约束位置

android:groupIndicator:显示在组列表旁边的Drawable对象,可以是一个图像

android:indicatorEnd:组列表项指示器的结束约束位置

android:indicatorLeft:组列表项指示器的左边约束位置

android:indicatorRight:组列表项指示器的右边约束位置

android:indicatorStart:组列表项指示器的开始约束位置

可以实现的ExpandableListView3种Adapter

1. 扩展BaseExpandableListAdpter实现ExpandableAdapter。

2. 使用SimpleExpandableListAdpater将两个List集合包装成ExpandableAdapter

3. 使用simpleCursorTreeAdapter

ExpandableListView的一些API详解

mExpandableListView.collapseGroup(position);   收起指定位置组的二级列表

mExpandableListView.expandGroup(position);  展开指定位置组的二级列表

mExpandableListView.isGroupExpanded(position);  指定位置的组是否展开

mExpandableListView.setSelectedGroup(position);  将指定位置的组设置为置顶

改变方向图标的位置

int width = getResources().getDisplayMetrics().widthPixels;
mExpandableListView.setIndicatorBounds(width - UnitConversionUtil.dip2px(this,40)
, width - UnitConversionUtil.dip2px(this,15));//设置图标位置

关于点击事件的一些坑

  如果你在适配器里去实现了Group的点击事件想用回调方法回调出去(如下代码),这个时候你就会碰到一个Group无法展开和收起的坑,原因很简单因为这里已经把点击事件消费了,点击不在继续向下传递,所以底层实现的展开和收起不执行了

  /**
* 返回一级父View
*/
@Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, final ViewGroup parent) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { }
});
return convertView;
}

那么如何解决呢?

方法一

  不用setOnClickListener(),因为这个会消费事件,我们改用setOnTouchListener,如下代码:

      convertView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN){
          //实现你自己的接口回调
}
return false;
}
});

  这里有一点需要注意ACTION_DOWN 需要返回false,因为底层是消费ACTION_DOWN的来展开和收起的....

方式二

将groupPosition回调到外面后使用collapseGroup() 或者 expandGroup()方法实现.

end

Android开发 ExpandableListView 可折叠列表详解的更多相关文章

  1. Android开发——事件分发机制详解

    0. 前言   转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52566965 深入学习事件分发机制,是为了解决在Android开发中 ...

  2. Android开发:程序目录结构详解

    HelloWorld程序的目录结构概述 我们可以在文件夹中看到,HelloWorld程序的目录主要包括:src文件夹.gen文件夹.Android文件夹.assets.res文件夹. AndroidM ...

  3. Android开发之位置定位详解与实例解析(GPS定位、Google网络定位,BaiduLBS(SDK)定位)

    在android开发中地图和定位是很多软件不可或缺的内容,这些特色功能也给人们带来了很多方便.定位一般分为三种发方案:即GPS定位.Google网络定位以及基站定位 最简单的手机定位方式当然是通过GP ...

  4. Android 开发 MaterialDialog框架的详解

    前言 开始之前还是需要废话一下,因为有一些坑需要告知.首先MaterialDialog在GitHub上作者已经转型使用100% Kotlin语言编写,虽然可以在Java里调用Kotlin使用.但是个人 ...

  5. Android开发——Activity启动模式详解

    1. Activity的启动模式 本文原创,转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52054893 1.1 Standard标 ...

  6. Android 开发 存储目录的详解

    简介 Android设备,有3个地方的文件存储位置,他们分别是: 内部存储空间(用户无法浏览到此目录) 外部存储空间(就是手机自身的文件管理目录,用户可以浏览) SD卡的存储空间(需要插入T卡) Sh ...

  7. android 开发 View _5_ Paint详解

    转载:http://blog.csdn.net/abcdef314159 //Paint的setStyle,Style共有3种 setStyle(Style style) Paint.Style.FI ...

  8. Android开发之线性布局详解(布局权重)

    布局权重 线性布局支持给个别的子视图设定权重,通过android:layout_weight属性.就一个视图在屏幕上占多大的空间而言,这个属性给其设 定了一个重要的值.一个大的权重值,允许它扩大到填充 ...

  9. Android开发——HandlerThread以及IntentService详解

    .HandlerThread Android API提供了HandlerThread来创建线程.官网的解释是: //Handy class for starting a new thread that ...

随机推荐

  1. 4.RabbitMQ Linux安装

    这里使用的Linux是CentOS6.2 将/etc/yum.repo.d/目录下的所有repo文件删除 先下载epel源 # wget -O  /etc/yum.repos.d/epel-erlan ...

  2. Java-javaFx库运用-时钟显示

    JavaFx是开发Java GUI程序的新框架.JavaFX应用可以无缝地在桌面或web浏览器中运行.具有内建的2D.3D动画支持,以及视频和音频的回放功能,可以作为一个应用独立运行或者在浏览器中运行 ...

  3. MFC-按行读取TXT数据

    TXT中数据格式如下: 1 23 4 0 4 10 …… 要实现的功能是:定义一个函数,每次调用时从TXT文档中读一个整数 ,赋值给变量.同时,文件位置向下移动一行,以便下次调用时读取下一行的数据. ...

  4. centos7.4安装kubernetes1.6.0(开启TLS认证)

    目录 目录 前言 集群详情 环境说明 安装前准备 提醒 一.创建TLS证书和秘钥 安装CFSSL 创建 CA (Certificate Authority) 创建 CA 配置文件 创建 CA 证书签名 ...

  5. linux mysql udf 提权

    连接远程数据库 查看插件库路径 show variables like '%plugin%'; 写入udf库到插件目录: 32位: select unhex('7F454C46020101000000 ...

  6. 【收集+】DDR5 vs DDR4

    Advantages of Migrating to DDR5 DDR5 is the next evolution in DRAM, bringing a robust list of new fe ...

  7. DLL相关下断点

    加载DLL 的时候断: sxe ld:[dll] 卸载DLL 的时候断: sxe ud:[dll] 比如: sxe ld:wininet.dll  (在wininet.dll 被装载的时候断点) 这里 ...

  8. 【ArcObject】 AxTocControl:实现图层可移动

    设置axTocControl属性:EnableLayerDragDrop 为true即可

  9. 2019-7-29-asp-dotnet-core-从-Frp-获取用户真实-IP-地址

    title author date CreateTime categories asp dotnet core 从 Frp 获取用户真实 IP 地址 lindexi 2019-07-29 08:28: ...

  10. 如何理解 if __name__ == "__main__"

    小明.py 朋友眼中你是小明(__name__ == '小明'), 你自己眼中你是你自己(__name__ == '__main__'), 你编程很好, 朋友调你去帮他写程序(import 小明, 这 ...