前言

  在需要实现一个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. 微信小程序--跳转页面常用的两种方法

    一.bindtap="onProductsItemTap"绑定点击跳转事件 在.wxml文件中绑定 在.js文件中实现绑定事件函数 二.navigator标签配合URL跳转法 在w ...

  2. 数据结构C++版-栈

    一.概念 二.应用实例 1.进制转换 #include <stdlib.h> #include <iostream> #include <string> #incl ...

  3. elasticsearch配置文件

    配置Elasticsearch的集群名称,默认是elasticsearch,Elasticsearch会自动发现在同一网段下的Elasticsearch 节点,如果在同一网段下有多个集群,就可以用这个 ...

  4. jsp-request应用1

    用jsp写表单提交数据时需要用到request去读取数据,表单代码如下: <form action="requestresult.jsp" method="post ...

  5. STM32F103

    memory map • Four masters: – Cortex® -M3 core DCode bus (D-bus) and System bus (S-bus)– GP-DMA1 & ...

  6. Android 7.0 IMS框架详解

    本文主要讲解IP Multimedia Subsystem (IMS)在Android 7.0上由谷歌Android实现的部分内容.从APP侧一直到Telephony Framework,是不区分CS ...

  7. 46张PPT弄懂JVM、GC算法和性能调优!

    来源:cnblogs.com/cyfonly/p/5807121.html 本PPT从JVM体系结构概述.GC算法.Hotspot内存管理.Hotspot垃圾回收器.调优和监控工具六大方面进行讲述. ...

  8. Number Sequence /// oj21456

    题目大意: 有一组规律数 the first 80 digits of the sequence are as follows: 1 12 123 1234 12345 123456 1234567 ...

  9. 收藏的链接-English

    What is the adverb for deposit? https://www.wordhippo.com/what-is/the-adverb-for/deposit.html

  10. Logstash2.3.4趟坑之集成Redis哨兵模式

    最新在使用Lostash2.3.4收集数据的时候,在读取redis数据的时候,报了如下的一个异常: 异常如下 Pipeline aborted due to error {:exception=> ...