在Android开发中,列表可以说是最常见的了,一般都是使用ListView,当涉及到二维数组时,更多的使用到ExpandableListView,然而当数据结构比较复杂时,就需要使用三级菜单或者更多级的菜单来显示,这就让人比较头疼了,最近做的项目就涉及到了三级菜单,遇到了不少问题,虽然不够完美,但是基本需求实现了,在此记录一下。(之前见过有人使用ListView实现4级、5级甚至更多级菜单的,是在Adapter的数据源里定义的结构,根据等级缩进左间距的倍数,链接地址找不到了,有兴趣的可以自己找找)
网站建设哪家好,找创新互联!专注于网页设计、网站建设、微信开发、小程序开发、集团企业网站建设等服务项目。为回馈新老客户创新互联还提供了海东免费建站欢迎大家使用!
先上效果图:


简单介绍下重点,为了简便,把第一层ExpandableListView称之为EListOne,相应的Adapter称之为AdpOne;第二层ExpandableListView称之为EListTwo,相应的Adapter称之为AdpTwo。
首先第一个要处理的问题是在AdpOne的getChildView方法中,需要对EListTwo的高度进行动态计算,因为EListTwo展开和关闭时高度是不一样的,所以要在EListTwo的setOnGroupExpandListener和setOnGroupCollapseListener方法中做相应的处理:
/**
* @author Apathy、恒
*
* 子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);
}
});
/**
* @author Apathy、恒
*
* 子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);
}
});只展示菜单肯定不是我们的最终需求,我们一般需要点击菜单后进行相应的界面跳转或者数据处理,所以就需要获取所点击的菜单精确下标,获取方法很简单,只需要定义一个接口,在AdpOne的getChildView方法中回调即可:
/**
* @author Apathy、恒
*
* 点击子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;
}
});
下面是完整的代码:
MainActivity.java:
package com.heng.tree; import java.util.ArrayList; import com.heng.tree.R; import com.heng.tree.adapter.ParentAdapter; import com.heng.tree.adapter.ParentAdapter.OnChildTreeViewClickListener; import com.heng.tree.entity.ChildEntity; import com.heng.tree.entity.ParentEntity; import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.os.Bundle; import android.widget.ExpandableListView; import android.widget.ExpandableListView.OnGroupExpandListener; import android.widget.Toast; /** * * @author Apathy、恒 * *
* * @email shexiaoheng@163.com * * @blog * http://blog.csdn.net/shexiaoheng * *
*
* * @Detail 本Demo为ExpandableListView嵌套ExpandableListView实现三级菜单的例子 * * #ParentAdapter.OnChildTreeViewClickListener * * */ public class MainActivity extends Activity implements OnGroupExpandListener, OnChildTreeViewClickListener { private Context mContext; private ExpandableListView eList; private ArrayListparents; private ParentAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = this; setContentView(R.layout.activity_main); loadData(); initEList(); } /** * @author Apathy、恒 * * 初始化菜单数据源 * */ private void loadData() { parents = new ArrayList (); for (int i = 0; i < 10; i++) { ParentEntity parent = new ParentEntity(); parent.setGroupName("父类父分组第" + i + "项"); parent.setGroupColor(getResources().getColor( android.R.color.holo_red_light)); ArrayList childs = new ArrayList (); for (int j = 0; j < 8; j++) { ChildEntity child = new ChildEntity(); child.setGroupName("子类父分组第" + j + "项"); child.setGroupColor(Color.parseColor("#ff00ff")); ArrayList childNames = new ArrayList (); ArrayList childColors = new ArrayList (); 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); } } /** * @author Apathy、恒 * * 初始化ExpandableListView * */ private void initEList() { eList = (ExpandableListView) findViewById(R.id.eList); eList.setOnGroupExpandListener(this); adapter = new ParentAdapter(mContext, parents); eList.setAdapter(adapter); adapter.setOnChildTreeViewClickListener(this); } /** * @author Apathy、恒 * * 点击子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(); } /** * @author Apathy、恒 * * 展开一项,关闭其他项,保证每次只能展开一项 * */ @Override public void onGroupExpand(int groupPosition) { for (int i = 0; i < parents.size(); i++) { if (i != groupPosition) { eList.collapseGroup(i); } } } }
ParentAdapter.java
package com.heng.tree.adapter; import java.util.ArrayList; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.ExpandableListView; import android.widget.ExpandableListView.OnChildClickListener; import android.widget.ExpandableListView.OnGroupCollapseListener; import android.widget.ExpandableListView.OnGroupExpandListener; import android.widget.AbsListView.LayoutParams; import android.widget.TextView; import com.heng.tree.R; import com.heng.tree.entity.ChildEntity; import com.heng.tree.entity.ParentEntity; /** * * @author Apathy、恒 * * 父类分组的适配器 * *
*
* * 方法 {@link #getChildView(int, int, boolean, View, ViewGroup)}极其重要 * * */ public class ParentAdapter extends BaseExpandableListAdapter { private Context mContext;// 上下文 private ArrayListmParents;// 数据源 private OnChildTreeViewClickListener mTreeViewClickListener;// 点击子ExpandableListView子项的监听 public ParentAdapter(Context context, ArrayList parents) { this.mContext = context; this.mParents = parents; } @Override public ChildEntity getChild(int groupPosition, int childPosition) { return mParents.get(groupPosition).getChilds().get(childPosition); } @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; } @Override public View getChildView(final int groupPosition, final int childPosition, boolean isExpanded, View convertView, ViewGroup parent) { final ExpandableListView eListView = getExpandableListView(); ArrayList childs = new ArrayList (); final ChildEntity child = getChild(groupPosition, childPosition); childs.add(child); final ChildAdapter childAdapter = new ChildAdapter(this.mContext, childs); eListView.setAdapter(childAdapter); /** * @author Apathy、恒 * * 点击子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; } }); /** * @author Apathy、恒 * * 子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); } }); /** * @author Apathy、恒 * * 子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; } /** * @author Apathy、恒 * * 动态创建子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; } @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.parent_group_item, null); holder = new GroupHolder(convertView); convertView.setTag(holder); } else { holder = (GroupHolder) convertView.getTag(); } holder.update(mParents.get(groupPosition)); return convertView; } /** * @author Apathy、恒 * * 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()); } } @Override public boolean hasStableIds() { return false; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return false; } /** * @author Apathy、恒 * * 设置点击子ExpandableListView子项的监听 * */ public void setOnChildTreeViewClickListener( OnChildTreeViewClickListener treeViewClickListener) { this.mTreeViewClickListener = treeViewClickListener; } /** * @author Apathy、恒 * * 点击子ExpandableListView子项的回调接口 * */ public interface OnChildTreeViewClickListener { void onClickPosition(int parentPosition, int groupPosition, int childPosition); } }
ChildAdapter.java
package com.heng.tree.adapter; import java.util.ArrayList; import com.heng.tree.R; import com.heng.tree.entity.ChildEntity; import android.content.Context; import android.graphics.Color; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.TextView; /** * * @author Apathy、恒 * *
*
* * 子类分组的适配器 * *
*
* * 方法{@link #isChildSelectable(int,int)} 必须返回true * * */ public class ChildAdapter extends BaseExpandableListAdapter { private Context mContext;// 上下文 private ArrayListmChilds;// 数据源 public ChildAdapter(Context context, ArrayList 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; } /** * @author Apathy、恒 * * 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; } /** * @author Apathy、恒 * * 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; } }
CListAdapter.java
package com.heng.tree.adapter;
import java.util.ArrayList;
import com.heng.tree.R;
import com.heng.tree.entity.ChildEntity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
/**
*
* @author Apathy、恒
*
* 子类子类列表的适配器
*
* */
public class CListAdapter extends BaseAdapter {
private Context mContext;
private ArrayList mChilds;
public CListAdapter(Context context, ArrayList childs) {
this.mContext = context;
this.mChilds = childs;
}
@Override
public int getCount() {
return mChilds != null ? mChilds.size() : 0;
}
@Override
public Object getItem(int position) {
if ((getCount() > 0) && (position > 0 && position < mChilds.size())) {
return mChilds.get(position);
}
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder = null;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(
R.layout.child_child_item, null);
holder = new Holder(convertView);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
}
holder.update(mChilds.get(position).getGroupName());
return convertView;
}
class Holder {
private TextView tv;
public Holder(View v) {
tv = (TextView) v.findViewById(R.id.childChildTV);
}
public void update(String text) {
tv.setText(text);
}
}
}
ParentEntity.java
package com.heng.tree.entity;
import java.util.ArrayList;
/**
*
* @author Apathy、恒
*
* 子类分组的实体
*
* */
public class ParentEntity {
private int groupColor;
private String groupName;
private ArrayList childs;
/* ==========================================================
* ======================= get method =======================
* ========================================================== */
public int getGroupColor() {
return groupColor;
}
public String getGroupName() {
return groupName;
}
public ArrayList 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 childs) {
this.childs = childs;
}
}
ChildEntity.java
package com.heng.tree.entity;
import java.util.ArrayList;
/**
*
* @author Apathy、恒
*
* 父类分组的实体
*
* */
public class ChildEntity {
private int groupColor;
private String groupName;
private ArrayList childNames;
/* ==========================================================
* ======================= get method =======================
* ========================================================== */
public int getGroupColor() {
return groupColor;
}
public String getGroupName() {
return groupName;
}
public ArrayList 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 childNames) {
this.childNames = childNames;
}
}
activity_main.xml
parent_group_item.xml
child_group_item.xml
child_child_item.xml
dimens.xml
50dp 10dp 40dp 75dp
点此下载demo
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持创新互联。