Android开发 ExpandableListView 可折叠列表详解
前言
在需要实现一个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 可折叠列表详解的更多相关文章
- Android开发——事件分发机制详解
0. 前言 转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52566965 深入学习事件分发机制,是为了解决在Android开发中 ...
- Android开发:程序目录结构详解
HelloWorld程序的目录结构概述 我们可以在文件夹中看到,HelloWorld程序的目录主要包括:src文件夹.gen文件夹.Android文件夹.assets.res文件夹. AndroidM ...
- Android开发之位置定位详解与实例解析(GPS定位、Google网络定位,BaiduLBS(SDK)定位)
在android开发中地图和定位是很多软件不可或缺的内容,这些特色功能也给人们带来了很多方便.定位一般分为三种发方案:即GPS定位.Google网络定位以及基站定位 最简单的手机定位方式当然是通过GP ...
- Android 开发 MaterialDialog框架的详解
前言 开始之前还是需要废话一下,因为有一些坑需要告知.首先MaterialDialog在GitHub上作者已经转型使用100% Kotlin语言编写,虽然可以在Java里调用Kotlin使用.但是个人 ...
- Android开发——Activity启动模式详解
1. Activity的启动模式 本文原创,转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52054893 1.1 Standard标 ...
- Android 开发 存储目录的详解
简介 Android设备,有3个地方的文件存储位置,他们分别是: 内部存储空间(用户无法浏览到此目录) 外部存储空间(就是手机自身的文件管理目录,用户可以浏览) SD卡的存储空间(需要插入T卡) Sh ...
- android 开发 View _5_ Paint详解
转载:http://blog.csdn.net/abcdef314159 //Paint的setStyle,Style共有3种 setStyle(Style style) Paint.Style.FI ...
- Android开发之线性布局详解(布局权重)
布局权重 线性布局支持给个别的子视图设定权重,通过android:layout_weight属性.就一个视图在屏幕上占多大的空间而言,这个属性给其设 定了一个重要的值.一个大的权重值,允许它扩大到填充 ...
- Android开发——HandlerThread以及IntentService详解
.HandlerThread Android API提供了HandlerThread来创建线程.官网的解释是: //Handy class for starting a new thread that ...
随机推荐
- C/Python/Java环境变量配置
链接 全图预览: Java: 只需添加下面三个环境变量即可使用Java.对照这我的添加就行. CLASSPATH的内容: .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\li ...
- nutch2.2.1+mysql抓取数据
基本环境:linux centos6.5 nutch2.2.1 源码包, mysql 5.5 ,elasticsearch1.1.1, jdk1.7 1.下载地址http://mirror.bjtu. ...
- Python匹马行天下之运算符
什么事运算符? 本章节主要说明Python的运算符.举个简单的例子 4 +5 = 9 . 例子中,4 和 5 被称为操作数,"+" 称为运算符. Python语言支持以下类型的运算 ...
- vue created与activated的区别
搬运自:https://www.cnblogs.com/goloving/p/9256212.html 使用<keep-alive>会将数据保留在内存中,如果要在每次进入页面的时候获取最新 ...
- MySQL 05章_模糊查询和聚合函数
在之前的查询都需要对查询的关机中进行“精确”.“完整”完整的输入才能查询相应的结果, 但在实际开发过程中,通常需要考虑用户可能不知道“精确”.“完整”的关键字, 那么就需要提供一种不太严格的查询方式, ...
- PHP出现报警后需要修改 date.timezone 的值(php.ini)
PHP调试的时候出现了警告: It is not safe to rely on the system解决方法,其实就是时区设置不正确造成的,本文提供了3种方法来解决这个问题. 实际上,从PHP 5. ...
- The linux command之高级键盘技巧
一.光标移动 二.修改文本 三.剪切和粘贴文本 四.使用历史命令
- JS随机产生颜色
<script> function selectForm(lowerValue,upperValue){ var choices=upperValue-lowerValue+1; retu ...
- thinkphp 系统流程
用户URL请求 调用应用入口文件(通常是网站的index.php) 载入框架入口文件(ThinkPHP.php) 记录初始运行时间和内存开销 系统常量判断及定义 载入框架引导类(Think\Think ...
- 分析post与json
寻找登录的post地址 在form表单中寻找action对应的url地址 post的数据是input标签中name的值作为键,真正的用户名密码作为值的字典,post的url地址就是action对应的u ...