ExpandableListView大家都不陌生,只是项目中会不会经常用到那就说不定了,也许你几年都没有使用过一次呢,那不是生疏了,下面来回顾一下ExpandableListView的使用吧:
那就以QQ为例吧,实现一个类似QQ的二级列表效果:
下面来看看怎么实现吧:
1.布局呈上:
直接看其属性:
divider:设置父类之间的分割线样式,具体的设置见childDivider
childDivider:用来设置同一个父项下,子类之间的分割线的样式
如:
android:childDivider="@drawable/child_divider"
若是要显示圆角的效果:
android:dividerHeight="5dp"
dividerHeight:用于设置分割线的高度
groupIndicator:用于控制父项前面的小箭头用的
若是不想箭头显示那就:
android:groupIndicator="@null"
indicatorLeft:箭头或者自己设置的图片的右边框距离手机左边边缘的距离,类似于marginLeft
indicatorStart:箭头或者自己设置的图片的左边框距离手机左边边缘的距离,类似于marginLeft
indicatorRight和indicatorEnd:箭头或者自己设置的图片的右边框距离手机右边边缘的距离
childIndicator:用于设置子项前显示的图标,不设置的话默认是没有图标的
2.主函数代码:
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_simple).setOnClickListener(this);
findViewById(R.id.btn_normal).setOnClickListener(this);
findViewById(R.id.btn_indicator).setOnClickListener(this);
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.btn_normal) {
startActivity(new Intent(this, NormalExpandActivity.class));
} else if (id == R.id.btn_indicator) {
startActivity(new Intent(this, IndicatorExpandActivity.class));
} else if(id== R.id.btn_simple){
startActivity(new Intent(this, SimpleExpandActivity.class));
}
}
}
3.自定义Indicator的ExpandableListView
/**
* 自定义 Indicator 的 ExpandableListView
*/
public class IndicatorExpandActivity extends AppCompatActivity {
private static final String TAG = "IndicatorExpandActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_expand);
final ExpandableListView listView = (ExpandableListView) findViewById(R.id.expandable_list);
final IndicatorExpandableListAdapter adapter = new IndicatorExpandableListAdapter(Constant.BOOKS, Constant.FIGURES);
listView.setAdapter(adapter);
// 清除默认的 Indicator
listView.setGroupIndicator(null);
// 设置分组项的点击监听事件
listView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
Log.d(TAG, "onGroupClick: groupPosition:" + groupPosition + ", id:" + id);
boolean groupExpanded = parent.isGroupExpanded(groupPosition);
adapter.setIndicatorState(groupPosition, groupExpanded);
// 请务必返回 false,否则分组不会展开
return false;
}
});
// 设置子选项点击监听事件
listView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
Toast.makeText(IndicatorExpandActivity.this, Constant.FIGURES[groupPosition][childPosition], Toast.LENGTH_SHORT).show();
return true;
}
});
}
}
对于处理 Item 的点击事件,常用的有这几类:
* setOnChildClickListener
* setOnGroupClickListener
* setOnGroupCollapseListener
* setOnGroupExpandListener
它们分别设置单击子选项、单击分组项、分组合并、分组展开的监听器。
4.IndicatorExpandableListAdapter
/**
* Indicator 的 ExpandableListView 的适配器
*/
public class IndicatorExpandableListAdapter extends BaseExpandableListAdapter {
private static final String TAG = "IndicatorExpandableList";
private String[] groupData;
private String[][] childData;
// 用于存放Indicator的集合
private SparseArray mIndicators;
private OnGroupExpandedListener mOnGroupExpandedListener;
public IndicatorExpandableListAdapter(String[] groupData, String[][] childData) {
this.groupData = groupData;
this.childData = childData;
mIndicators = new SparseArray<>();
}
public void setOnGroupExpandedListener(OnGroupExpandedListener onGroupExpandedListener) {
mOnGroupExpandedListener = onGroupExpandedListener;
}
// 根据分组的展开闭合状态设置指示器
public void setIndicatorState(int groupPosition, boolean isExpanded) {
if (isExpanded) {
mIndicators.get(groupPosition).setImageResource(R.drawable.ic_expand_less);
} else {
mIndicators.get(groupPosition).setImageResource(R.drawable.ic_expand_more);
}
}
@Override
public int getGroupCount() {
return groupData.length;
}
@Override
public int getChildrenCount(int groupPosition) {
return childData[groupPosition].length;
}
@Override
public Object getGroup(int groupPosition) {
return groupData[groupPosition];
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return childData[groupPosition][childPosition];
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
GroupViewHolder groupViewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_expand_group_indicator, parent, false);
groupViewHolder = new GroupViewHolder();
groupViewHolder.tvTitle = (TextView) convertView.findViewById(R.id.label_group_indicator);
groupViewHolder.ivIndicator = (ImageView) convertView.findViewById(R.id.iv_indicator);
convertView.setTag(groupViewHolder);
} else {
groupViewHolder = (GroupViewHolder) convertView.getTag();
}
groupViewHolder.tvTitle.setText(groupData[groupPosition]);
// 把位置和图标添加到Map
mIndicators.put(groupPosition, groupViewHolder.ivIndicator);
// 根据分组状态设置Indicator
setIndicatorState(groupPosition, isExpanded);
return convertView;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View
convertView, ViewGroup parent) {
ChildViewHolder childViewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_expand_child, parent, false);
childViewHolder = new ChildViewHolder();
childViewHolder.tvTitle = (TextView) convertView.findViewById(R.id.label_expand_child);
convertView.setTag(childViewHolder);
} else {
childViewHolder = (ChildViewHolder) convertView.getTag();
}
childViewHolder.tvTitle.setText(childData[groupPosition][childPosition]);
return convertView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
@Override
public void onGroupExpanded(int groupPosition) {
Log.d(TAG, "onGroupExpanded() called with: groupPosition = [" + groupPosition + "]");
if (mOnGroupExpandedListener != null) {
mOnGroupExpandedListener.onGroupExpanded(groupPosition);
}
}
@Override
public void onGroupCollapsed(int groupPosition) {
Log.d(TAG, "onGroupCollapsed() called with: groupPosition = [" + groupPosition + "]");
}
private static class GroupViewHolder {
TextView tvTitle;
ImageView ivIndicator;
}
private static class ChildViewHolder {
TextView tvTitle;
}
}
5.适配器布局:
6.普通的二级列表形式:
/**
* 普通 ExpandableListView,支持只展开一个子项
*/
public class NormalExpandActivity extends AppCompatActivity {
private static final String TAG = "NormalExpandActivity";
private ExpandableListView mExpandableListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_expand);
mExpandableListView = (ExpandableListView) findViewById(R.id.expandable_list);
final NormalExpandableListAdapter adapter = new NormalExpandableListAdapter(Constant.BOOKS, Constant.FIGURES);
mExpandableListView.setAdapter(adapter);
adapter.setOnGroupExpandedListener(new OnGroupExpandedListener() {
@Override
public void onGroupExpanded(int groupPosition) {
expandOnlyOne(groupPosition);
}
});
// 设置分组项的点击监听事件
mExpandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
Log.d(TAG, "onGroupClick: groupPosition:" + groupPosition + ", id:" + id);
// 请务必返回 false,否则分组不会展开
return false;
}
});
// 设置子选项点击监听事件
mExpandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
Toast.makeText(NormalExpandActivity.this, Constant.FIGURES[groupPosition][childPosition], Toast.LENGTH_SHORT).show();
return true;
}
});
}
// 每次展开一个分组后,关闭其他的分组
private boolean expandOnlyOne(int expandedPosition) {
boolean result = true;
int groupLength = mExpandableListView.getExpandableListAdapter().getGroupCount();
for (int i = 0; i < groupLength; i++) {
if (i != expandedPosition && mExpandableListView.isGroupExpanded(i)) {
result &= mExpandableListView.collapseGroup(i);
}
}
return result;
}
}
适配器:
/**
* 普通的 ExpandableListView 的适配器
*/
public class NormalExpandableListAdapter extends BaseExpandableListAdapter {
private static final String TAG = "NormalExpandableListAda";
private String[] groupData;
private String[][] childData;
private OnGroupExpandedListener mOnGroupExpandedListener;
public NormalExpandableListAdapter(String[] groupData, String[][] childData) {
this.groupData = groupData;
this.childData = childData;
}
public void setOnGroupExpandedListener(OnGroupExpandedListener onGroupExpandedListener) {
mOnGroupExpandedListener = onGroupExpandedListener;
}
@Override
public int getGroupCount() {
return groupData.length;
}
@Override
public int getChildrenCount(int groupPosition) {
return childData[groupPosition].length;
}
@Override
public Object getGroup(int groupPosition) {
return groupData[groupPosition];
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return childData[groupPosition][childPosition];
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View
convertView, ViewGroup parent) {
GroupViewHolder groupViewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_expand_group_normal, parent, false);
groupViewHolder = new GroupViewHolder();
groupViewHolder.tvTitle = (TextView) convertView.findViewById(R.id.label_group_normal);
convertView.setTag(groupViewHolder);
} else {
groupViewHolder = (GroupViewHolder) convertView.getTag();
}
groupViewHolder.tvTitle.setText(groupData[groupPosition]);
return convertView;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View
convertView, ViewGroup parent) {
ChildViewHolder childViewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_expand_child, parent, false);
childViewHolder = new ChildViewHolder();
childViewHolder.tvTitle = (TextView) convertView.findViewById(R.id.label_expand_child);
convertView.setTag(childViewHolder);
} else {
childViewHolder = (ChildViewHolder) convertView.getTag();
}
childViewHolder.tvTitle.setText(childData[groupPosition][childPosition]);
return convertView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
@Override
public void onGroupExpanded(int groupPosition) {
Log.d(TAG, "onGroupExpanded() called with: groupPosition = [" + groupPosition + "]");
if (mOnGroupExpandedListener != null) {
mOnGroupExpandedListener.onGroupExpanded(groupPosition);
}
}
@Override
public void onGroupCollapsed(int groupPosition) {
Log.d(TAG, "onGroupCollapsed() called with: groupPosition = [" + groupPosition + "]");
}
private static class GroupViewHolder {
TextView tvTitle;
}
private static class ChildViewHolder {
TextView tvTitle;
}
}
7.使用 SimpleExpandableListAdapter 实现适配器
/**
* 使用 SimpleExpandableListAdapter 实现适配器
*/
public class SimpleExpandActivity extends AppCompatActivity {
private static final String TAG = "SimpleExpandActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_expand);
ExpandableListView listView = (ExpandableListView) findViewById(R.id.expandable_list);
SimpleExpandableListAdapter adapter = new SimpleExpandableListAdapter(this, initGroupData(),
R.layout.item_expand_group_normal, new String[]{Constant.BOOK_NAME}, new int[]{R.id.label_group_normal},
initChildData(), R.layout.item_expand_child, new String[]{Constant.FIGURE_NAME}, new int[]{R.id.label_expand_child});
listView.setAdapter(adapter);
// 设置分组项的点击监听事件
listView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
Log.d(TAG, "onGroupClick: groupPosition:" + groupPosition + ", id:" + id);
// 请务必返回 false,否则分组不会展开
return false;
}
});
// 设置子选项点击监听事件
listView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
Toast.makeText(SimpleExpandActivity.this, Constant.FIGURES[groupPosition][childPosition], Toast.LENGTH_SHORT).show();
return true;
}
});
}
// 构建分组项显示的数据
private List
8.分组展开监听器:
/**
* 分组展开监听器
*/
public interface OnGroupExpandedListener {
/**
* 分组展开
*
* @param groupPosition 分组的位置
*/
void onGroupExpanded(int groupPosition);
}
9.常量:
/**
* 常量类
*/
public final class Constant {
public static final String[] BOOKS = {"我的朋友", "我的闺蜜", "我的女朋友", "我的妹妹"};
public static final String[][] FIGURES = {
{"我的朋友有很多所以就不一一介绍了,就算介绍了你也不一定认识!"},
{"我的闺蜜有很多所以就不一一介绍了,就算介绍了你也不一定认识!"},
{"小翠", "小玉", "小群", "小莫", "..."},
{"小染", "小静", "小莉", "小华","..."}
};
public static final String BOOK_NAME = "book_name";
public static final String FIGURE_NAME = "figure_name";
}
下载链接:点击下载案例
最后再贴一个常用的完整的小Demo(点击第一条时,其他条目都关闭):
1.主函数:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.ExpandableListView.OnGroupClickListener;
import android.widget.ExpandableListView.OnGroupExpandListener;
import android.widget.Toast;
public class MainActivity extends Activity {
private ExpandableListView expandableListView;
String[] groupNames = { "大陆明星", "香港明星", "美国明星" };
String[][] childNames = new String[][] { { "刘涛", "胡歌", "范冰冰" },
{ "成龙", "周润发", "张国荣", "陈小春", "刘德华" },
{ "史泰龙", "施瓦辛格", "奥黛丽·赫本", "安吉丽娜朱莉" } };
int[][] childIcons = new int[][] {
{ R.drawable.ad, R.drawable.ae, R.drawable.af },
{ R.drawable.al, R.drawable.am, R.drawable.an, R.drawable.ao,
R.drawable.ag },
{ R.drawable.ad, R.drawable.ae, R.drawable.af, R.drawable.bg } };
private Drawable[] groupIcons;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 添加资源
groupIcons = new Drawable[] {
getResources().getDrawable(R.drawable.aa),
getResources().getDrawable(R.drawable.ab),
getResources().getDrawable(R.drawable.ac) };
expandableListView = (ExpandableListView) findViewById(R.id.elv);
// 设置数据适配器
expandableListView.setAdapter(new MyExpandableAdapter(this, groupNames,
childNames, groupIcons, childIcons));
expandableListView
.setOnGroupExpandListener(new OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
// 当打开的时候,设置小图标为反向
// expandableListView.setGroupIndicator(getResources()
// .getDrawable(R.drawable.ic_launcher2));
// 当打开自己的时候,关闭别人
for (int i = 0; i < groupNames.length; i++) {
if (groupPosition != i) {
// 关闭
expandableListView.collapseGroup(i);
}
}
}
});
/**
* 监听点击了哪个孩子
*/
expandableListView.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
String string = childNames[groupPosition][childPosition];
Toast.makeText(MainActivity.this, string, Toast.LENGTH_SHORT).show();
// 是否消费(处理)该点击事件
return true;
}
});
/**
* 组的点击事件
*/
expandableListView.setOnGroupClickListener(new OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
Toast.makeText(MainActivity.this,
"第" + groupPosition + "组被点击了", Toast.LENGTH_SHORT).show();
return false;
}
});
// expandableListView
// .setOnGroupCollapseListener(new OnGroupCollapseListener() {
// @Override
// public void onGroupCollapse(int groupPosition) {
// // 当打开的时候,设置小图标为反向
// expandableListView.setGroupIndicator(getResources()
// .getDrawable(R.drawable.ic_launcher));
// }
// });
}
}
2.适配器:
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class MyExpandableAdapter extends BaseExpandableListAdapter {
private Context context;
private String[] groupNames;
private Drawable[] groupIcon;
private int[][] childIcons;
private String[][] childNames;
public MyExpandableAdapter(Context context, String[] groupNames,
String[][] childNames, Drawable[] groupIcon, int[][] childIcons) {
this.context = context;
this.groupNames = groupNames;
this.groupIcon = groupIcon;
this.childNames = childNames;
this.childIcons = childIcons;
}
/**
* 获取孩子的内容
*/
@Override
public Object getChild(int groupPosition, int childPosition) {
return childNames[groupPosition][childPosition];
}
/**
* 返回孩子的id
*/
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
/**
* 孩子的布局视图
*/
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
View view = View.inflate(context, R.layout.child_item, null);
ImageView iv_child = (ImageView) view.findViewById(R.id.iv_child);
TextView tv_child = (TextView) view.findViewById(R.id.tv_child);
iv_child.setImageResource(childIcons[groupPosition][childPosition]);
tv_child.setText(childNames[groupPosition][childPosition]);
return view;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
View view = View.inflate(context, R.layout.group_item, null);
ImageView iv_group = (ImageView) view.findViewById(R.id.iv_group);
TextView tv_group = (TextView) view.findViewById(R.id.tv_group);
// 获取组的图标
iv_group.setImageDrawable(groupIcon[groupPosition]);
tv_group.setText(groupNames[groupPosition]);
return view;
}
/**
* 返回每一组孩子的个数
*/
@Override
public int getChildrenCount(int groupPosition) {
// 先获取孩子所在数组,然后获取每一组的长度
return childNames[groupPosition].length;
}
/**
* 返回组的内容
*/
@Override
public Object getGroup(int groupPosition) {
return groupNames[groupPosition];
}
/**
* 获取组的个数
*/
@Override
public int getGroupCount() {
return groupNames.length;
}
/**
* 获取组的id
*/
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
/**
* 是否有唯一的id
*/
@Override
public boolean hasStableIds() {
return true;
}
/**
* 孩子是否可选
*/
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
3.布局:
activity_main.xml:
child_item.xml
group_item.xml