ExpandableListView是一个垂直滚动显示两级列表项的视图,与ListView不同的是,它可以有两层:每一层都能够被独立的展开并显示其子项。这些子项来自于与该视图关联的BaseExpandableListAdapter。
有时候简单的ExpandableListView不能满足我们的需求,比如下面这样的需求:
这就需要在ExpandableListView里面再嵌套一个ListView来实现。首先需要重写一个ListView,代码如下:
public class SubListView extends ListView {
public SubListView(android.content.Context context,
android.util.AttributeSet attrs) {
super(context, attrs);
}
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
主要是重写onMeasure方法,这里将heightMeasureSpec参数设大,否则,嵌套的ListView会显示不全。
然后重写我们的BaseExpandableListAdapter,代码如下:
class ExpandAdapter extends BaseExpandableListAdapter {
private Context context;
private ArrayList<ArrayList<String>> childList;
private ArrayList<String> groupList;
private LayoutInflater inflater;
public ExpandAdapter(Context context, ArrayList<String> groupList,
ArrayList<ArrayList<String>> childList) {
this.childList = childList;
this.groupList = groupList;
this.context = context;
inflater = LayoutInflater.from(context);
}
@Override
public int getGroupCount() {
// TODO Auto-generated method stub
return groupList.size();
}
@Override
public int getChildrenCount(int groupPosition) {
// TODO Auto-generated method stub
// return childList.get(groupPosition).size();
return 1;
}
@Override
public Object getGroup(int groupPosition) {
// TODO Auto-generated method stub
return groupList.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return childList.get(groupPosition).get(childPosition);
}
@Override
public long getGroupId(int groupPosition) {
// TODO Auto-generated method stub
return 0;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return 0;
}
@Override
public boolean hasStableIds() {
// TODO Auto-generated method stub
return true;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View groupView = null;
if (convertView == null) {
groupView = newGroupView(parent);
} else {
groupView = convertView;
}
bindGroupView(groupPosition, groupView);
return groupView;
}
private View newGroupView(ViewGroup parent) {
return inflater.inflate(R.layout.group_item_layout, null);
}
private void bindGroupView(int groupPosition, View groupView) {
TextView tv = (TextView) groupView.findViewById(R.id.name_text);
tv.setText(groupList.get(groupPosition));
ImageView iv = (ImageView) groupView
.findViewById(R.id.image_avatar);
iv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(context, "Hello!", Toast.LENGTH_SHORT)
.show();
}
});
}
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View childView = null;
if (convertView == null) {
childView = newChildView(parent, groupPosition);
} else {
childView = convertView;
}
bindChildView(groupPosition, childPosition, childView);
return childView;
}
private View newChildView(ViewGroup parent, final int groupPosition) {
View v = inflater.inflate(R.layout.child_layout, null);
SubListView listView = (SubListView) v.findViewById(R.id.sublistview);
View foot = inflater.inflate(R.layout.foot_layout, null);
listView.addFooterView(foot);
// final SubListAdapter adapter = new
// SubListAdapter(treeNodes.get(groupPosition).childs,layoutInflater);
final SubListAdapter adapter = new SubListAdapter(
childList.get(groupPosition), inflater);
listView.setAdapter(adapter);// 设置菜单Adapter
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
// if(position ==
// treeNodes.get(groupPosition).childs.size()){//foot的点击事件处理
// treeNodes.get(groupPosition).childs.add("New Add");
// adapter.notifyDataSetChanged();
// }else{
// Toast.makeText(parentContext, "当前选中的是:" + position,
// Toast.LENGTH_SHORT).show();
// }
if (position == childList.get(groupPosition).size()) {// foot的点击事件处理
childList.get(groupPosition).add("New Add");
adapter.notifyDataSetChanged();
} else {
Toast.makeText(ExpandableListViewActivity.this,
"当前选中的是:" + position, Toast.LENGTH_SHORT)
.show();
}
}
});
return v;
}
private void bindChildView(int groupPosition, int childPosition,
View groupView) {
// TextView tv = (TextView) groupView.findViewById(R.id.name_text);
// tv.setText(childList.get(groupPosition).get(childPosition));
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return true;
}
}
这里需要注意的是在getChildrenCount方法里要返回1,不然就会每个二级View里就会生成很多ListView。加载很多其实就是靠ListView的foot的点击事件来处理的。
这里对ExpandableListView也做了一些其他的处理,一并记录下。第一个是将一级View的指示符号放到里右面并且进行了自定义。放到右面的方法如下:
<span style="font-size: 18px;">int width = getWindowManager().getDefaultDisplay().getWidth();
expandableListView.setIndicatorBounds(width - 100, width - 10);</span>
自定义指示符的方法是在res/drawable下自定义一个xml命名为indicator.xml,如下:
<span style="font-size: 18px;"><?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_expanded="true" android:drawable="@drawable/add_btn_small" />
<item android:state_expanded="false" android:drawable="@drawable/head32_32" />
</selector></span>
然后在我们的layout里做以下处理:
<span style="font-size: 18px;">android:groupIndicator="@drawable/indicator"</span>
这样就会显示我们自定义的View了,需要注意的一点是这里的图片容易拉伸,最好用.9的图。
第二个问题是默认将ExpandableListView默认打开,这个就比较简单了,
private void expandView() {
for (int i = 0; i < groupList.size(); i++) {
expandableListView.expandGroup(i);
}
}