上一篇我们介绍了ExpandableListView多级列表的二级列表,见天我们分析下多级列表(三级)的情况。我们先看下效果图:
通过效果图分析:这是一个三级列表分类 ,主要是由ExpandableListView 控件实现,和上一篇二级列表相似。下面我们看一下代码:
1.先看一下主类的xml文件 和 主代码:通过ExpandableListView实现。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.fanhaichao.myapplication.MainActivity">
<ExpandableListView
android:id="@+id/eList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:groupIndicator="@null" />
</RelativeLayout>
再看下代码:
/**
* @email shexiaoheng@163.com
* @blog <a href='http://blog.csdn.net/shexiaoheng'>http://blog.csdn.net/shexiaoheng</a >
* @Detail 本Demo为ExpandableListView嵌套ExpandableListView实现三级菜单的例子
* #ParentAdapter.OnChildTreeViewClickListener
*/
public class MainActivity extends AppCompatActivity implements ExpandableListView.OnGroupExpandListener, ParentAdapter.OnChildTreeViewClickListener {
private Context mContext;
private ExpandableListView eList;
private ArrayList<ParentEntity> parents;
private ParentAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
loadData();//获取数据,假数据
initEList();//初始化
}
/**
* 初始化菜单数据源
*/
private void loadData() {
parents = new ArrayList<ParentEntity>();
for (int i = 0; i < 15; i++) {
ParentEntity parent = new ParentEntity(); //父类对象
parent.setGroupName("父类父分组第" + i + "项");//假数据 ,设置一级列表数据
parent.setGroupColor(getResources().getColor(android.R.color.holo_red_light));//红色 ,一级列表颜色
ArrayList<ChildEntity> childs = new ArrayList<ChildEntity>();
for (int j = 0; j < 10; j++) {
ChildEntity child = new ChildEntity(); //子类对象
child.setGroupName("子类父分组第" + j + "项");//假数据 ,二级列表数据
child.setGroupColor(Color.parseColor("#ff00ff"));//紫色 二级列表颜色
ArrayList<String> childNames = new ArrayList<String>();
ArrayList<Integer> childColors = new ArrayList<Integer>();
for (int k = 0; k < 5; k++) {
childNames.add("子类第" + k + "项");//假数据 三级列表数据
childColors.add(Color.parseColor("#ff00ff"));//紫色
}
child.setChildNames(childNames);
childs.add(child);
}
parent.setChilds(childs);
parents.add(parent);
}
}
/**
* 初始化ExpandableListView
*/
private void initEList() {
eList = (ExpandableListView) findViewById(R.id.eList);
eList.setOnGroupExpandListener(this);
adapter = new ParentAdapter(mContext, parents);//父类分组适配器
eList.setAdapter(adapter);
adapter.setOnChildTreeViewClickListener(this);//设置条目点击事件
}
/**
* 点击子ExpandableListView的子项时,回调本方法,根据下标获取值来做相应的操作
*/
@Override
public void onClickPosition(int parentPosition, int groupPosition, int childPosition) {
// do something
String childName = parents.get(parentPosition).getChilds()
.get(groupPosition).getChildNames().get(childPosition)
.toString();
Toast.makeText(
mContext,
"点击的下标为: parentPosition=" + parentPosition
+ " groupPosition=" + groupPosition
+ " childPosition=" + childPosition + "\n点击的是:"
+ childName, Toast.LENGTH_SHORT).show();
}
/**
* 展开一项,关闭其他项,保证每次只能展开一项
*/
@Override
public void onGroupExpand(int groupPosition) {
for (int i = 0; i < parents.size(); i++) {
if (i != groupPosition) {
eList.collapseGroup(i);//关闭状态
}
}
}
}
2.看下 父类分组的适配器 ParentAdapter 及 xml 文件。
/**
* 父类分组的适配器
* 方法 {@link #getChildView(int, int, boolean, View, ViewGroup)}
* color='#ff00ff' size='2'>极其重要
*/
public class ParentAdapter extends BaseExpandableListAdapter {
private Context mContext;// 上下文
private ArrayList<ParentEntity> mParents;// 数据源
private OnChildTreeViewClickListener mTreeViewClickListener;// 点击子ExpandableListView子项的监听
public ParentAdapter(Context context, ArrayList<ParentEntity> parents) {
this.mContext = context;
this.mParents = parents;
}
// 获得某个父项的某个子项
@Override
public ChildEntity getChild(int groupPosition, int childPosition) {
return mParents.get(groupPosition).getChilds().get(childPosition);
}
// 获得某个父项的某个子项的id
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
// 获得某个父项的子项数目
@Override
public int getChildrenCount(int groupPosition) {
return mParents.get(groupPosition).getChilds() != null ? mParents.get(groupPosition).getChilds().size() : 0;
}
// 获得子项显示的view
@Override
public View getChildView(final int groupPosition, final int childPosition, boolean isExpanded, View convertView, ViewGroup parent) {
final ExpandableListView eListView = getExpandableListView();
ArrayList<ChildEntity> childs = new ArrayList<ChildEntity>();
final ChildEntity child = getChild(groupPosition, childPosition);
childs.add(child);
final ChildAdapter childAdapter = new ChildAdapter(this.mContext, childs);//三级列表adapter
eListView.setAdapter(childAdapter);
/**
*点击子ExpandableListView子项时,调用回调接口
*/
eListView.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView arg0, View arg1, int groupIndex, int childIndex, long arg4) {
if (mTreeViewClickListener != null) {
mTreeViewClickListener.onClickPosition(groupPosition, childPosition, childIndex);
}
return false;
}
});
/**
* 子ExpandableListView展开时,因为group只有一项,所以子ExpandableListView的总高度=
* (子ExpandableListView的child数量 + 1 )* 每一项的高度
*/
eListView.setOnGroupExpandListener(new OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (child.getChildNames().size() + 1) * (int) mContext.getResources().getDimension(R.dimen.parent_expandable_list_height));
eListView.setLayoutParams(lp);
}
});
/**
* 子ExpandableListView关闭时,此时只剩下group这一项,
* 所以子ExpandableListView的总高度即为一项的高度
*/
eListView.setOnGroupCollapseListener(new OnGroupCollapseListener() {
@Override
public void onGroupCollapse(int groupPosition) {
LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) mContext.getResources().getDimension(R.dimen.parent_expandable_list_height));
eListView.setLayoutParams(lp);
}
});
return eListView;
}
/**
* 动态创建子ExpandableListView
*/
public ExpandableListView getExpandableListView() {
ExpandableListView mExpandableListView = new ExpandableListView(mContext);
LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) mContext.getResources().getDimension(R.dimen.parent_expandable_list_height));
mExpandableListView.setLayoutParams(lp);
mExpandableListView.setDividerHeight(0);// 取消group项的分割线
mExpandableListView.setChildDivider(null);// 取消child项的分割线
mExpandableListView.setGroupIndicator(null);// 取消展开折叠的指示图标
return mExpandableListView;
}
// 获得某个父项
@Override
public Object getGroup(int groupPosition) {
return mParents.get(groupPosition);
}
// 获得父项的数量
@Override
public int getGroupCount() {
return mParents != null ? mParents.size() : 0;
}
// 获得某个父项的id
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
// 获得父项显示的view
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
GroupHolder holder = null;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.parent_group_item, null);
holder = new GroupHolder(convertView);
convertView.setTag(holder);
} else {
holder = (GroupHolder) convertView.getTag();
}
holder.update(mParents.get(groupPosition));
return convertView;
}
/**
* Holder优化
*/
class GroupHolder {
private TextView parentGroupTV;
public GroupHolder(View v) {
parentGroupTV = (TextView) v.findViewById(R.id.parentGroupTV);
}
public void update(ParentEntity model) {
parentGroupTV.setText(model.getGroupName());
parentGroupTV.setTextColor(model.getGroupColor());
}
}
// 按函数的名字来理解应该是是否具有稳定的id,这个方法目前一直都是返回false,没有去改动过
@Override
public boolean hasStableIds() {
return false;
}
// 子项是否可选中,如果需要设置子项的点击事件,需要返回true
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
/**
* 设置点击子ExpandableListView子项的监听
*/
public void setOnChildTreeViewClickListener(OnChildTreeViewClickListener treeViewClickListener) {
this.mTreeViewClickListener = treeViewClickListener;
}
/**
* 点击子ExpandableListView子项的回调接口
*/
public interface OnChildTreeViewClickListener {
void onClickPosition(int parentPosition, int groupPosition, int childPosition);
}
}
布局文件 parent_group_item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/parent_expandable_list_group_padding_left" >
<TextView
android:id="@+id/parentGroupTV"
android:layout_width="wrap_content"
android:layout_height="@dimen/parent_expandable_list_height"
android:gravity="center_vertical" />
</RelativeLayout>
oK,这里我们哟格外注意:getExpandableListView() 方法.
/**
* 动态创建子ExpandableListView
*/
public ExpandableListView getExpandableListView() {
ExpandableListView mExpandableListView = new ExpandableListView(mContext);
LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) mContext.getResources().getDimension(R.dimen.parent_expandable_list_height));
mExpandableListView.setLayoutParams(lp);
mExpandableListView.setDividerHeight(0);// 取消group项的分割线
mExpandableListView.setChildDivider(null);// 取消child项的分割线
mExpandableListView.setGroupIndicator(null);// 取消展开折叠的指示图标
return mExpandableListView;
}
3.看一下 子类分组适配器 ChildAdapter 及 xml 文件。
/**
* 子类分组的适配器
* 方法{@link #isChildSelectable(int, int)} color='#ff00ff'
* size='2'>必须返回true
*/
public class ChildAdapter extends BaseExpandableListAdapter {
private Context mContext;// 上下文
private ArrayList<ChildEntity> mChilds;// 数据源
public ChildAdapter(Context context, ArrayList<ChildEntity> childs) {
this.mContext = context;
this.mChilds = childs;
}
@Override
public int getChildrenCount(int groupPosition) {
return mChilds.get(groupPosition).getChildNames() != null ? mChilds.get(groupPosition).getChildNames().size() : 0;
}
@Override
public String getChild(int groupPosition, int childPosition) {
if (mChilds.get(groupPosition).getChildNames() != null && mChilds.get(groupPosition).getChildNames().size() > 0)
return mChilds.get(groupPosition).getChildNames().get(childPosition).toString();
return null;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isExpanded, View convertView, ViewGroup parent) {
ChildHolder holder = null;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.child_child_item, null);
holder = new ChildHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ChildHolder) convertView.getTag();
}
holder.update(getChild(groupPosition, childPosition));
return convertView;
}
/**
* Holder优化
*/
class ChildHolder {
private TextView childChildTV;
public ChildHolder(View v) {
childChildTV = (TextView) v.findViewById(R.id.childChildTV);
}
public void update(String str) {
childChildTV.setText(str);
childChildTV.setTextColor(Color.parseColor("#00ffff"));//蓝色
}
}
@Override
public Object getGroup(int groupPosition) {
if (mChilds != null && mChilds.size() > 0)
return mChilds.get(groupPosition);
return null;
}
@Override
public int getGroupCount() {
return mChilds != null ? mChilds.size() : 0;
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
GroupHolder holder = null;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.child_group_item, null);
holder = new GroupHolder(convertView);
convertView.setTag(holder);
} else {
holder = (GroupHolder) convertView.getTag();
}
holder.update(mChilds.get(groupPosition));
return convertView;
}
/**
* Holder优化
*/
class GroupHolder {
private TextView childGroupTV;
public GroupHolder(View v) {
childGroupTV = (TextView) v.findViewById(R.id.childGroupTV);
}
public void update(ChildEntity model) {
childGroupTV.setText(model.getGroupName());
childGroupTV.setTextColor(model.getGroupColor());
}
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
/**
* ==============================================
* 此处必须返回true,否则无法响应子项的点击事件===============
* ==============================================
**/
return true;
}
}
布局文件 child_group_item.xml 及 child_child_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/parent_expandable_list_height" >
<TextView
android:id="@+id/childGroupTV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="@dimen/child_expandable_list_group_padding_left" />
</RelativeLayout>
</LinearLayout>
child_child_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/parent_expandable_list_height" >
<TextView
android:id="@+id/childChildTV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="@dimen/child_expandable_list_child_padding_left" />
</RelativeLayout>
</LinearLayout>
然后看下父类及子类的实体类
/**
* 子类分组的实体
*/
public class ParentEntity {
private int groupColor;
private String groupName;
private ArrayList<ChildEntity> childs;
/* ==========================================================
* ======================= get method =======================
* ========================================================== */
public int getGroupColor() {
return groupColor;
}
public String getGroupName() {
return groupName;
}
public ArrayList<ChildEntity> getChilds() {
return childs;
}
/* ==========================================================
* ======================= set method =======================
* ========================================================== */
public void setGroupColor(int groupColor) {
this.groupColor = groupColor;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public void setChilds(ArrayList<ChildEntity> childs) {
this.childs = childs;
}
/**
* 父类分组的实体
*/
public class ChildEntity {
private int groupColor;
private String groupName;
private ArrayList<String> childNames;
/* ==========================================================
* ======================= get method =======================
* ========================================================== */
public int getGroupColor() {
return groupColor;
}
public String getGroupName() {
return groupName;
}
public ArrayList<String> getChildNames() {
return childNames;
}
/* ==========================================================
* ======================= set method =======================
* ========================================================== */
public void setGroupColor(int groupColor) {
this.groupColor = groupColor;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public void setChildNames(ArrayList<String> childNames) {
this.childNames = childNames;
}
}
最后看下dimens.xml
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="parent_expandable_list_height">50dp</dimen>
<dimen name="parent_expandable_list_group_padding_left">10dp</dimen>
<dimen name="child_expandable_list_group_padding_left">40dp</dimen>
<dimen name="child_expandable_list_child_padding_left">75dp</dimen>
</resources>
除此之外我们参考下:http://blog.csdn.net/shexiaoheng/article/details/41351247
http://blog.csdn.net/sysukehan/article/details/51960473