在一般的开发中,ListView是用的比较频繁的了,然而有些时候,我们不得不涉及到数据的二层展示,类似下面:
那么对于类似这种效果的,我们用 ExpandableListView,二级列表就能很好的展示出来了。OK,下面就以上面的效果为例,讲一讲 ExpandableListView的基本使用
1.首先看 MainActivity 的 xml 文件
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/FrameLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ExpandableListView
android:id="@+id/expandableListView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ExpandableListView>
</FrameLayout>
很简单,就是在布局中放一个 ExpandableListView 控件
好的,在来看看 MainActivity 的 实现;
一开始当然是声明 和 初始化了:
public class MainActivity extends Activity{
private ExpandableListView mExpandableListView;
private List<School>mSchools;
private ExAdapter mExAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("","=====create====");
initView();
initData();
setListener();
}
private void initView() {
mExpandableListView=(ExpandableListView) findViewById(R.id.expandableListView1);
}
好的,接下来再讲 initData 方法之前,要先抛出一个数据对象,在后面的数据展示将用到
public class School implements Serializable{
private String title;
private List<String>detailList;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getDetailList() {
return detailList;
}
public void setDetailList(List<String> detailList) {
this.detailList = detailList;
}
}
这个类很简单,不做多解释,OK,接下来讲 initData的实现:
private void initData() {
mSchools=new ArrayList<School>();
School schoolOne=new School();
schoolOne.setTitle("大学");
List<String>bigList=new ArrayList<String>();
bigList.add("北京大学");
bigList.add("武汉大学");
bigList.add("复旦大学");
schoolOne.setDetailList(bigList);
mSchools.add(schoolOne);
School schoolTwo=new School();
schoolTwo.setTitle("中学");
List<String>middleList=new ArrayList<String>();
middleList.add("华师附中");
middleList.add("北京二中");
schoolTwo.setDetailList(middleList);
mSchools.add(schoolTwo);
mExAdapter=new ExAdapter(mSchools, this);
mExpandableListView.setAdapter(mExAdapter);
//去掉系统箭头
// mExpandableListView.setGroupIndicator(null);
}
这个方法也不复杂,前面一半是数据填充,adapter的使用和ListView的使用方法基本一致,那么接下来的关键是 ExAdapter 的实现了,先丢出 ExAdapter 代码
package com.example.test;
import java.util.List;
import com.example.androidtexta.MainActivity;
import com.example.androidtexta.R;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
import android.widget.Toast;
public class ExAdapter extends BaseExpandableListAdapter{
private List<School>mDatas;
private Context mContext;
public ExAdapter(List<School>datas,Context context){
this.mDatas=datas;
this.mContext=context;
}
@Override
public int getGroupCount() {
// TODO Auto-generated method stub
return mDatas==null?0:mDatas.size();
}
@Override
public int getChildrenCount(int groupPosition) {
if(mDatas==null||mDatas.isEmpty()){
return 0;
}
return mDatas.get(groupPosition).getDetailList()==null?0:mDatas.get(groupPosition).getDetailList().size();
}
@Override
public Object getGroup(int groupPosition) {
// TODO Auto-generated method stub
return mDatas==null?null:mDatas.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
if(mDatas==null||mDatas.isEmpty()){
return null;
}
return mDatas.get(groupPosition).getDetailList()==null?null:mDatas.get(groupPosition).getDetailList().get(childPosition);
}
@Override
public long getGroupId(int groupPosition) {
// TODO Auto-generated method stub
return mDatas==null?0:groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
if(mDatas==null||mDatas.isEmpty()){
return 0;
}
return mDatas.get(groupPosition).getDetailList()==null?0:childPosition;
}
@Override
public boolean hasStableIds() {
// TODO Auto-generated method stub
return true;
}
/**ExpandableListView 如果子条目需要响应click事件,必需返回true*/
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return true;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
GroupHolder groupHolder;
if(convertView==null){
groupHolder=new GroupHolder();
convertView=LayoutInflater.from(mContext).inflate(R.layout.adapter_group, null);
convertView.setTag(groupHolder);
}else{
groupHolder=(GroupHolder) convertView.getTag();
}
groupHolder.title=(TextView) convertView.findViewById(R.id.tv_title);
School school=mDatas.get(groupPosition);
groupHolder.title.setText(school.getTitle());
return convertView;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ChildHolder childHolder;
if(convertView==null){
childHolder=new ChildHolder();
convertView=LayoutInflater.from(mContext).inflate(R.layout.adapter_child, null);
convertView.setTag(childHolder);
}else{
childHolder=(ChildHolder) convertView.getTag();
}
childHolder.detail=(TextView) convertView.findViewById(R.id.tv_detail);
String middleMsg=mDatas.get(groupPosition).getDetailList().get(childPosition);
childHolder.detail.setText(middleMsg);
return convertView;
}
class GroupHolder{
TextView title;
}
class ChildHolder{
TextView detail;
}
}
代码很长,需要注意的是 ExpandableListView 对应个 adapter 不再是 BaseAdapter 了,而是 BaseExpandableListAdapter 。虽然 adapter 变了,可是大部分方法还是差不多的,这里检些比较陌生的来讲讲
首先是 hasStableIds() ,对于此方法不是很熟,经查阅,得出的结果如下:
这样说把. 通知ListView, 你id是唯一的. 不会重复,
默认这个方法是返回false的, 需要返回true. 这样, 才能使用ListView的CHOICE_MODE_MULTIPLE, CHOICE_MODE_SINGLE, 通过getCheckedItemIds方法才能正常获取用户选中的选项的id, LZ可以试试看
这个的意思就是你的每个item中元素的id是否稳定,如果你用position当id ,那就是不稳定的,如果有自己特定的id那就是稳定的 就是干这个用的
再看看 isChildSelectable(int groupPosition, int childPosition) 方法,他的作用是为了让 ExpandableListView 的 二级菜单响应 点击事件,返回 true 时,ExpandableListView的二级列表的点击事件会响应,返回false时,点击 ExpandableListView 的二级列表是没反应的,所以一般返回 true
ok,再来看看 ExpandableListView 的点击事件,回到 MainActivity 中 看 setListener 方法:
private void setListener() {
//一级点击事件
mExpandableListView.setOnGroupClickListener(new OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
boolean flag=mExpandableListView.isGroupExpanded(groupPosition);
Toast.makeText(MainActivity.this, mSchools.get(groupPosition).getTitle(), 0).show();
if(flag){
Log.i("","一级列表收起");
}else{
Log.i("","一级列表展开");
}
return false;
}
});
//二级点击事件(mExAdapter中的isChildSelectable()方法需要返回true)
mExpandableListView.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
String detail=mSchools.get(groupPosition).getDetailList().get(childPosition);
Toast.makeText(MainActivity.this, detail, 0).show();
return false;
}
});
}
好吧,再看瞧瞧两个点击事件都做了些什么:
注意看一级点击事件中的 flag,它是一级列表是否已经展开的判断标准,当我们自定义 下拉箭头时会用到,当然,自定义的时候,需要设置 mExpandableListView.setGroupIndicator(null);,禁用系统箭头
二级点击事件主要需要注意的就是 adapter中的 isChildSelectable 要返回true 了,
最后,附上 MainActivity 界面的代码:
package com.example.androidtexta;
import java.util.ArrayList;
import java.util.List;
import com.example.test.ExAdapter;
import com.example.test.School;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.ExpandableListView.OnGroupClickListener;
import android.widget.Toast;
public class MainActivity extends Activity{
private ExpandableListView mExpandableListView;
private List<School>mSchools;
private ExAdapter mExAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("","=====create====");
initView();
initData();
setListener();
}
private void initView() {
mExpandableListView=(ExpandableListView) findViewById(R.id.expandableListView1);
}
private void initData() {
mSchools=new ArrayList<School>();
School schoolOne=new School();
schoolOne.setTitle("大学");
List<String>bigList=new ArrayList<String>();
bigList.add("北京大学");
bigList.add("武汉大学");
bigList.add("复旦大学");
schoolOne.setDetailList(bigList);
mSchools.add(schoolOne);
School schoolTwo=new School();
schoolTwo.setTitle("中学");
List<String>middleList=new ArrayList<String>();
middleList.add("华师附中");
middleList.add("北京二中");
schoolTwo.setDetailList(middleList);
mSchools.add(schoolTwo);
mExAdapter=new ExAdapter(mSchools, this);
mExpandableListView.setAdapter(mExAdapter);
//去掉系统箭头
// mExpandableListView.setGroupIndicator(null);
}
private void setListener() {
//一级点击事件
mExpandableListView.setOnGroupClickListener(new OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
boolean flag=mExpandableListView.isGroupExpanded(groupPosition);
Toast.makeText(MainActivity.this, mSchools.get(groupPosition).getTitle(), 0).show();
if(flag){
Log.i("","一级列表收起");
}else{
Log.i("","一级列表展开");
}
return false;
}
});
//二级点击事件(mExAdapter中的isChildSelectable()方法需要返回true)
mExpandableListView.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
String detail=mSchools.get(groupPosition).getDetailList().get(childPosition);
Toast.makeText(MainActivity.this, detail, 0).show();
return false;
}
});
}
@Override
protected void onDestroy(){
super.onDestroy();
}
}
OK,结束!