ExpandableListView多及列表(三级列表)

上一篇我们介绍了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


源码:http://download.csdn.net/detail/shexiaoheng/8212209

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值