1. ExpandableListView简介
下拉列表(可扩展的列表控件)在App应用非常常见,在Android开发中是我们必须掌握的一个控件,下面就来介绍一下ExpandableListView这个控件的开发。
ExpandableListView分为组列表项和子列表项,单击组列表项,会显示这组里所有的子列表项。和ListView一样,它也是通过Adapter数据适配器完成数据与显示的衔接,但它使用的另一种接口:ExpandableListAdapter.
今天我们要做的是实现一个继承它的父接口:BaseExpandableListAdapter的类,来实现自定义的下拉列表(就是如同ListView里的方式,给它的列表项设置界面布局文件layout)。
2. 示例
示例包含四个文件,两个Java文件和两个layout文件。Java文件包含一个Activity,和我们自己实现的MyExpandAdapter;layout文件一个是用于Activity,另一个就是子列表项的界面布局文件,至于组列表项的布局,我们通过直接在代码里创建一个TextView来实现,这样,就同时介绍了下拉列表样式实现的两种方法。
plan_manager.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ExpandableListView
android:id="@+id/expandableListView_plan_manager"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ExpandableListView>
</LinearLayout>
布局文件,添加控件
PlanManager.java
package com.plan;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ExpandableListView;
import android.widget.Toast;
import com.example.plan.R;
public class PlanManager extends Activity{
ExpandableListView sp_date_list = null; //列表
MyExpandAdapter adapter = null; //数据适配器
List<String> group_head; //组列表项,每个组都有一个子List
List<List<String>> child; //子列表项
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.plan_manger);
//获取控件
sp_date_list = (ExpandableListView)findViewById(R.id.expandableListView_plan_manager);
//初始化组、子列表项
group_head = new ArrayList<String>();
child = new ArrayList<List<String>>();
//设置适配器
sp_date_list.setAdapter(new MyExpandAdapter(this,group_head,child)); //设置数据适配器
sp_date_list.setCacheColorHint(0); //拖动列表的时候不出现黑色背景
addGroup("静夜思");
addGroup("春晓");
addChild(0,"床前明月光");
addChild(0,"疑是地上霜");
addChild(1,"春眠不觉晓");
addChild(1,"处处闻啼鸟");
}
//添加组列表项
public void addGroup(String group){
group_head.add(group);
child.add(new ArrayList<String>()); //child中添加新数组
}
//添加对应组的自列表项
public void addChild(int position,String child){
List<String> it = this.child.get(position);
if(it != null){
it.add(child);
}else{
it = new ArrayList<String>();
it.add(child);
}
}
//子列表项被选中的响应方法
public void childSelect(int groupPosition,int childPosition){
Toast.makeText(getBaseContext(), Integer.toString(groupPosition)+":" +
Integer.toString(childPosition), 2000).show();
}
}
查找控件,连接显示与适配器,并添加一些示例数据,其中的addGroup和addChild以及childSelect可以提供给其他组件作为接口
plain_text.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="@+id/textView_plain_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
这是子列表项的布局文件,因为只是简单示例,太复杂了的话学起来麻烦,所以只用了一个文本框,在实际项目中可以多加几个控件,改一下child的类型(最好改成map映射)就好
MyExpandAdapter.java
package com.plan;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
import com.example.plan.R;
public class MyExpandAdapter extends BaseExpandableListAdapter{
List<String> group_head;
List<List<String>> child;
PlanManager context;
public MyExpandAdapter(Context content){
//初始化组、子列表项
group_head = new ArrayList<String>();
child = new ArrayList<List<String>>();
}
public MyExpandAdapter(PlanManager context,List<String> group_head,
List<List<String>> child){
this.context = context;
//初始化组、子列表项
this.group_head = group_head;
this.child = child;
}
@Override
public int getGroupCount() {
// TODO Auto-generated method stub
return this.group_head.size();
}
@Override
public int getChildrenCount(int position) {
// TODO Auto-generated method stub
if(position<0||position>=this.child.size())
return 0;
return child.get(position).size();
}
@Override
public Object getGroup(int groupPosition) {
// TODO Auto-generated method stub
return group_head.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return child.get(childPosition).get(childPosition);
}
@Override
public long getGroupId(int groupPosition) {
// TODO Auto-generated method stub
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return childPosition;
}
@Override
public boolean hasStableIds() {
// TODO Auto-generated method stub
return true;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
//获取文本
String text = group_head.get(groupPosition);
if(convertView == null){
//组列表界面只有一个文本框,直接生成
convertView = new TextView(context);
//设定界面,AbsListView:用于实现条目的虚拟列表的基类
AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, 60);
((TextView) convertView).setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); //文本框放在中央
convertView.setPadding(45, 0, 0, 0); //设置文本里那个下拉的图标远一点
convertView.setLayoutParams(lp);
Log.d("Group", text);
}
((TextView) convertView).setText(text);
return convertView;
}
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
//子列表控件通过界面文件设计
if(convertView ==null){//convert在运行中会重用,如果不为空,则表明不用重新获取
LayoutInflater layoutInflater;//使用这个来载入界面
layoutInflater = LayoutInflater.from(context);
convertView = layoutInflater.inflate(R.layout.plain_text, null);
}
TextView tv = (TextView)convertView.findViewById(R.id.textView_plain_text);
String text = child.get(groupPosition).get(childPosition);
tv.setText(text);
//获取文本控件,并设置值
return convertView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
//调用Activity里的ChildSelect方法
context.childSelect(groupPosition,childPosition);
return true;
}
}
继承接口后,Eclipse可以自动生成这些方法,我们只需要改一下就好。里面有些地方用到了Log.d方法,用于在logcat里输出日志(也可用System.out.println),主要是用来优化一下程序,通过看日志打印了几次,就可以看出程序中的方法是否有被重复调用。