作者:邹峰立,微博:zrunker,邮箱:zrunker@yahoo.com,微信公众号:书客创作,个人平台:www.ibooker.cc。
书客创作
ExpandableListView可扩展列表,或者称其为二级列表,它能够完美的实现二级列表的显示和隐藏。也是应用中常见的控件之一。ExpandableListView继承ListView,在实现二级列表方面表现优异,不适合多级列表的实现。那么该如何使用ExpandableListView实现一个完整的二级列表呢?
下面将以一个小案例说明ExpandableListView是如何使用。首先看看效果图:
一、XML布局文件
ExpandableListView是Android SDK自带的一个控件,该控件继承自ListView,所以ListView的相关属性,它基本上都适合,但不是全部。
1、添加ExpandableListView到XML布局文件activity_main.xml
<ExpandableListView
android:id="@+id/alarm_clock_expandablelist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:childDivider="#c8c7cc"
android:divider="@null"
android:dividerHeight="1dp"
android:gravity="center"
android:listSelector="#ffffff"
android:scrollbars="none" />
2、一级列表布局activity_main _father.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical">
<TextView
android:id="@+id/alarm_clock_father_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:padding="10dp"
android:textSize="18sp" />
<ImageView
android:id="@+id/group_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginBottom="3dp"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="3dp"
android:contentDescription="@null" />
</RelativeLayout>
3、二级列表布局activity_main _children.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginStart="10dp"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/alarm_clock_tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp" />
<TextView
android:id="@+id/alarm_clock_tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="13sp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:contentDescription="@null"
android:src="@drawable/right" />
</RelativeLayout>
二、创建列表数据对象
1、一级列表数据对象,这里封装了对应二级列表数据。
public class FatherData {
private String title;
private ArrayList<ChildrenData> list;// 二级列表数据
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public ArrayList<ChildrenData> getList() {
return list;
}
public void setList(ArrayList<ChildrenData> list) {
this.list = list;
}
}
2、二级列表数据对象。
public class ChildrenData {
private String Desc;
private String title;
public String getDesc() {
return Desc;
}
public void setDesc(String desc) {
Desc = desc;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
三、自定义Adapter
自定义ExPandableListView的适配器需要继承BaseExpandableListAdapter 。并实现一级列表和二级列表的相关处理方法。
public class ExPandableListViewAdapter extends BaseExpandableListAdapter {
// 定义一个Context
private Context context;
// 定义一个LayoutInflater
private LayoutInflater mInflater;
// 定义一个List来保存列表数据
private ArrayList<FatherData> data_list = new ArrayList<>();
// 定义一个构造方法
public ExPandableListViewAdapter(Context context, ArrayList<FatherData> datas) {
this.context = context;
this.mInflater = LayoutInflater.from(context);
this.data_list = datas;
}
// 刷新数据
public void flashData(ArrayList<FatherData> datas) {
this.data_list = datas;
this.notifyDataSetChanged();
}
// 获取二级列表的内容
@Override
public Object getChild(int arg0, int arg1) {
return data_list.get(arg0).getList().get(arg1);
}
// 获取二级列表的ID
@Override
public long getChildId(int arg0, int arg1) {
return arg1;
}
// 定义二级列表中的数据
@Override
public View getChildView(int arg0, int arg1, boolean arg2, View arg3, ViewGroup arg4) {
// 定义一个二级列表的视图类
HolderView childrenView;
if (arg3 == null) {
childrenView = new HolderView();
// 获取子视图的布局文件
arg3 = mInflater.inflate(R.layout.activity_main_children, arg4, false);
childrenView.titleView = (TextView) arg3.findViewById(R.id.alarm_clock_tv1);
childrenView.descView = (TextView) arg3.findViewById(R.id.alarm_clock_tv2);
// 这个函数是用来将holderview设置标签,相当于缓存在view当中
arg3.setTag(childrenView);
} else {
childrenView = (HolderView) arg3.getTag();
}
/**
* 设置相应控件的内容
*/
// 设置标题上的文本信息
childrenView.titleView.setText(data_list.get(arg0).getList().get(arg1).getTitle());
// 设置副标题上的文本信息
childrenView.descView.setText(data_list.get(arg0).getList().get(arg1).getDesc());
return arg3;
}
// 保存二级列表的视图类
private class HolderView {
TextView titleView;
TextView descView;
}
// 获取二级列表的数量
@Override
public int getChildrenCount(int arg0) {
return data_list.get(arg0).getList().size();
}
// 获取一级列表的数据
@Override
public Object getGroup(int arg0) {
return data_list.get(arg0);
}
// 获取一级列表的个数
@Override
public int getGroupCount() {
return data_list.size();
}
// 获取一级列表的ID
@Override
public long getGroupId(int arg0) {
return arg0;
}
// 设置一级列表的view
@Override
public View getGroupView(int arg0, boolean arg1, View arg2, ViewGroup arg3) {
HodlerViewFather hodlerViewFather;
if (arg2 == null) {
hodlerViewFather = new HodlerViewFather();
arg2 = mInflater.inflate(R.layout.activity_main_father, arg3, false);
hodlerViewFather.titlev = (TextView) arg2.findViewById(R.id.alarm_clock_father_tv);
// 新建一个TextView对象,用来显示一级标签上的大体描述的信息
hodlerViewFather.group_state = (ImageView) arg2.findViewById(R.id.group_state);
arg2.setTag(hodlerViewFather);
} else {
hodlerViewFather = (HodlerViewFather) arg2.getTag();
}
// 一级列表右侧判断箭头显示方向
if (arg1) {
hodlerViewFather.group_state.setImageResource(R.drawable.group_down);
} else {
hodlerViewFather.group_state.setImageResource(R.drawable.group_up);
}
/**
* 设置相应控件的内容
*/
// 设置标题上的文本信息
hodlerViewFather.titlev.setText(data_list.get(arg0).getTitle());
// 返回一个布局对象
return arg2;
}
// 定义一个 一级列表的view类
private class HodlerViewFather {
TextView titlev;
ImageView group_state;
}
/**
* 指定位置相应的组视图
*/
@Override
public boolean hasStableIds() {
return true;
}
/**
* 当选择子节点的时候,调用该方法(点击二级列表)
*/
@Override
public boolean isChildSelectable(int arg0, int arg1) {
return true;
}
}
四、Activity实现
ExPandableListView提供对一级列表和二级列表的点击事件监听,分别是OnGroupClickListener、OnChildClickListener。
public class MainActivity extends AppCompatActivity {
private ExpandableListView myExpandableListView;
private ExPandableListViewAdapter adapter;
private ArrayList<FatherData> datas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
setData();
setAdapter();
}
// 初始化控件
private void initView() {
myExpandableListView = (ExpandableListView) findViewById(R.id.alarm_clock_expandablelist);
// 设置ExpandableListView的监听事件
// 设置一级item点击的监听器
myExpandableListView.setOnGroupClickListener(new OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, datas.get(arg2).getTitle(), Toast.LENGTH_LONG).show();
return false;
}
});
// 设置二级item点击的监听器,同时在Adapter中设置isChildSelectable返回值true,同时二级列表布局中控件不能设置点击效果
myExpandableListView.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView arg0, View arg1, int arg2, int arg3, long arg4) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, datas.get(arg2).getList().get(arg3).getTitle(), Toast.LENGTH_LONG).show();
return false;
}
});
}
/**
* 自定义setAdapter
*/
private void setAdapter() {
if (adapter == null) {
adapter = new ExPandableListViewAdapter(this, datas);
myExpandableListView.setAdapter(adapter);
} else {
adapter.flashData(datas);
}
}
// 定义数据
private void setData() {
if (datas == null) {
datas = new ArrayList<>();
}
// 一级列表中的数据
for (int i = 0; i < 5; i++) {
FatherData fatherData = new FatherData();
fatherData.setTitle("闹钟列表" + i);
// 二级列表中的数据
ArrayList<ChildrenData> itemList = new ArrayList<>();
for (int j = 0; j < 3; j++) {
ChildrenData childrenData = new ChildrenData();
childrenData.setTitle("闹钟主题" + j);
childrenData.setDesc(j + ":30");
itemList.add(childrenData);
}
fatherData.setList(itemList);
datas.add(fatherData);
}
}
}
以上便是实现可扩展列表的基本使用规则。
ExPandableListView其他设置
(1)、去掉默认带的箭头
expandlistView.setGroupIndicator(null);
(2)、设置默认选中项
expandlistView.setSelection(0);
(3)、所有项设置成默认展开
// 遍历所有group,将所有项设置成默认展开
int groupCount = expandlistView.getCount();
for (int i = 0; i < groupCount; i++) {
expandlistView.expandGroup(i);
}
ExPandableListView常见问题
在开发过程常常会遇到ExPandableListView二级列表点击没有反应,那么该如何正确实现二级列表的点击事件呢?
一、需要在Adapter复写isChildSelectable方法,设置返回值为true。
@Override
public boolean isChildSelectable(int arg0, int arg1) {
return true;
}
二、如果这样二级列表点击还没有效果的话,检查看看二级布局文件是不是设置了布局点击事件,如果二级列表布局已经设置了点击事件就去掉布局的点击事件。
三、如果以上两种方式都处理了,还是无法设置二级列表的点击事件,那就检查二级列表布局文件中是否含有像ToggleButton这样原本就具有点击效果的控件,如果有就去掉。
微信公众号:书客创作
网友评论