参考自Android小白
http://blog.csdn.net/sysukehan/article/details/51960473
MainActivity 的布局 layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Hello World!"
android:gravity="center"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ExpandableListView
android:id="@+id/expandlistview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>
<Button
android:id="@+id/updateData"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="10dp"
android:textSize="20dp"
android:layout_gravity="center"
android:text="刷新数据"/>
</LinearLayout>
</LinearLayout>
<!--需要使分割线消失的话,不要将这两个属性设置为@null,-->
<!--把它们的颜色设置为与背景颜色相同的颜色即可。-->
<!--如果想要用自己的图片替换掉那个箭头可以这样写
android:groupIndicator="@drawable/picture"
android:groupIndicator="@null"
childIndicator
用于设置子项前显示的图标,不设置的话默认是没有图标的
-->
父项的布局文件 layout/parent_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/parent_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
子类的布局文件 layout/child_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/child_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
具体实现代码如下:
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseExpandableListAdapter;
import android.widget.Button;
import android.widget.ExpandableListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
ExpandableListView expandview;
Map<String,List<String>> listMap = new HashMap<>();
String[] parentList = new String[]{"first","second","third"};
List<String> childList1 = new ArrayList<>();
List<String> childList2 = new ArrayList<>();
List<String> childList3 = new ArrayList<>();
private Button button;
BaseExpandableListAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
expandview = (ExpandableListView) findViewById(R.id.expandlistview);
button = (Button) findViewById(R.id.updateData);
//设置childList的数据
childList1.add(parentList[0]+"first");
childList1.add(parentList[1]+"first");
childList1.add(parentList[2]+"first");
childList2.add(parentList[0]+"first");
childList2.add(parentList[1]+"first");
childList2.add(parentList[2]+"first");
childList3.add(parentList[0]+"first");
childList3.add(parentList[1]+"first");
childList3.add(parentList[2]+"first");
listMap.put(parentList[0],childList1);
listMap.put(parentList[1],childList2);
listMap.put(parentList[2],childList3);
//设置适配器
adapter = new MyExpandableListAdapter(this);
expandview.setAdapter(adapter);
// 这里在每个子项被点击了之后会显示是哪个子项被点击了
// 特别注意
//(1)在使用这个方法的时候需要将自定义的adapter中的isChildSelectable方法的返回值设置为true,
// 否则子项的点击不生效,但子项布局中设置的控件的监听器依然可以生效。
// // 子项是否可选中,如果需要设置子项的点击事件,需要返回true
// @Override
// public boolean isChildSelectable(int i, int i1) {
// return true;
// }
//(2)如果在子项中对某个控件设置了监听器,这个控件要注意不能铺满整个子项,
// 所以在设置高度和宽度时要特别注意,否则设置了子项的监听器也是没有用的
expandview.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView expandableListView, View view,
int parentPos, int childPos, long l) {
Toast.makeText(MainActivity.this,
listMap.get(parentList[parentPos]).get(childPos), Toast.LENGTH_SHORT).show();
return true;
}
});
// 然后设置ExpandableListView长按item的监听器:
expandview.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
String content = "";
if ((int) view.getTag(R.layout.child_item) == -1) {
content = "父类第" + view.getTag(R.layout.parent_item) + "项" + "被长按了";
} else {
content = "父类第" + view.getTag(R.layout.parent_item) + "项" + "中的"
+ "子类第" + view.getTag(R.layout.child_item) + "项" + "被长按了";
}
Toast.makeText(MainActivity.this, content, Toast.LENGTH_SHORT).show();
return true;
}
});
//设置listview的展开和伸缩
expandview.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
Toast.makeText(MainActivity.this, "第" + groupPosition + "个列表伸展了", Toast.LENGTH_SHORT).show();
}
});
expandview.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
@Override
public void onGroupCollapse(int groupPosition) {
Toast.makeText(MainActivity.this, "第" + groupPosition + "个列表收缩了", Toast.LENGTH_SHORT).show();
}
});
// 如果需要进入的时候列表就展开,然后不再收起,可以这样设置:
// 《1》在setAdapter之后遍历每一个列表使它们展开
// 《2》然后设置父类的监听器直接返回true即可,不可以设置父类的监听器为null,
// 那样起不到屏蔽原先系统设置的监听器的效果
for (int i = 0; i < parentList.length; i++){
if (!expandview.isGroupExpanded(i)) {
expandview.expandGroup(i);
}
}
expandview.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView expandableListView, View view, int i, long l) {
// 用于判断列表是否展开的方法
// if (expandview.isGroupExpanded(i)) {//列表已展开,返回true;列表未展开,返回false
// expandview.collapseGroup(i);
// } else {
//// 如果把这个参数设置为true,列表展开的时候会有动画效果,该方法需在API大于等于14的时候才可以用
// expandview.expandGroup(i, true);
// }
return true;
}
});
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
updateData();
Toast.makeText(MainActivity.this, "数据已更新", Toast.LENGTH_SHORT).show();
}
});
}
private void updateData() {
childList1.clear();
childList1.add(parentList[0] + "-new-" + "first");
childList1.add(parentList[0] + "-new-" + "second");
childList1.add(parentList[0] + "-new-" + "third");
childList2.clear();
childList2.add(parentList[1] + "-new-" + "first");
childList2.add(parentList[1] + "-new-" + "second");
childList2.add(parentList[1] + "-new-" + "third");
childList3.clear();
childList3.add(parentList[2] + "-new-" + "first");
childList3.add(parentList[2] + "-new-" + "second");
childList3.add(parentList[2] + "-new-" + "third");
//刷新适配器
adapter.notifyDataSetChanged();
}
private class MyExpandableListAdapter extends BaseExpandableListAdapter {
Context mcontext;
LayoutInflater inflater;
public MyExpandableListAdapter(Context context) {
mcontext = context;
inflater = LayoutInflater.from(context);
}
//获取父项的数据
@Override
public int getGroupCount() {
return listMap.size();
}
//获取子项的数据
@Override
public int getChildrenCount(int groupPosition) {
return listMap.get(parentList[groupPosition]).size();
}
//获取某个父项
@Override
public Object getGroup(int groupPosition) {
return listMap.get(parentList[groupPosition]);
}
//获取某个父项的某个子项
@Override
public Object getChild(int groupPosition, int childPosition) {
return listMap.get(parentList[groupPosition]).get(childPosition);
}
//获取某个父项的id
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
//获取某个子项的id
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
// 按函数的名字来理解应该是是否具有稳定的id,这个方法目前一直都是返回false,没有去改动过
@Override
public boolean hasStableIds() {
return false;
}
// 当expandlistview的getGroupView或者getChildView中包含checkbox时,前者点击不可用。
// 解决办法 在etGroupView或者getChildView的checkbox中添加
// android:clickable="true"
// android:focusable="false"
// android:focusableInTouchMode="false"
// 获得父项显示的view
// ExpandableListView 的 数据适配器 ExpandableListAdapter 中的
// getGroupView 函数中所引入的自定义一级目录xml 布局文件不能带有 button,
// 否则会导致展开失效,ImageButton没尝试过,不过可能也是不行的。
// 这里用到了view的setTag方法,一共设置了两个Tag,
// 标签虽然在设置的时候提示说只要int类型即可,但一开始使用0和1来做tag的时候,
// 显示没有报错,但编译运行就报错了,要求是资源文件的id才行,
// 因此换成了R.layout.parent_item和R.layout.child_item。
// 如果是父项,就设置R.layout.parent_item为第几个父项,
// 设置R.layout.child_item为-1。如果是子项,就设置R.layout.parent_item属于第几个父项
// 设置R.layout.child_item为该父项的第几个子项,这样就可以区分被长按的是父项还是子项
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.parent_item, null);
}
convertView.setTag(R.layout.parent_item, groupPosition);
convertView.setTag(R.layout.child_item, -1);
TextView text = (TextView) convertView.findViewById(R.id.parent_title);
text.setText(parentList[groupPosition]);
return convertView;
}
// 获得子项显示的view
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null){
convertView = inflater.inflate(R.layout.child_item, null);
}
convertView.setTag(R.layout.parent_item, groupPosition);
convertView.setTag(R.layout.child_item, childPosition);
TextView text = (TextView) convertView.findViewById(R.id.child_title);
text.setText(listMap.get(parentList[groupPosition]).get(childPosition));
text.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(mcontext, "点到了内置的textview", Toast.LENGTH_SHORT).show();
}
});
return convertView;
}
// 子项是否可选中,如果需要设置子项的点击事件,需要返回true
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
}