追溯-----ExpandableListView,二级列表的基本使用

本文介绍如何使用Android中的ExpandableListView实现多层次的数据展示,并提供了一级和二级列表项的点击事件处理示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在一般的开发中,ListView是用的比较频繁的了,然而有些时候,我们不得不涉及到数据的二层展示,类似下面:


那么对于类似这种效果的,我们用 ExpandableListView,二级列表就能很好的展示出来了。OK,下面就以上面的效果为例,讲一讲 ExpandableListView的基本使用


1.首先看 MainActivity 的 xml 文件

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/FrameLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ExpandableListView
        android:id="@+id/expandableListView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ExpandableListView>
    
</FrameLayout>

很简单,就是在布局中放一个  ExpandableListView 控件


好的,在来看看  MainActivity 的 实现;

一开始当然是声明 和 初始化了:

public class MainActivity extends Activity{
	
	private ExpandableListView mExpandableListView;
	private List<School>mSchools;
	private ExAdapter mExAdapter;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		Log.i("","=====create====");

		initView();
		initData();
		setListener();
	}

	private void initView() {
		mExpandableListView=(ExpandableListView) findViewById(R.id.expandableListView1);
	    
	}

好的,接下来再讲 initData 方法之前,要先抛出一个数据对象,在后面的数据展示将用到

public class School implements Serializable{
   
	private String title;
	private List<String>detailList;
	
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public List<String> getDetailList() {
		return detailList;
	}
	public void setDetailList(List<String> detailList) {
		this.detailList = detailList;
	}
}

这个类很简单,不做多解释,OK,接下来讲 initData的实现:

	private void initData() {
		mSchools=new ArrayList<School>();
		School schoolOne=new School();
		schoolOne.setTitle("大学");
		List<String>bigList=new ArrayList<String>();
		bigList.add("北京大学");
		bigList.add("武汉大学");
		bigList.add("复旦大学");
		schoolOne.setDetailList(bigList);
		mSchools.add(schoolOne);
		
		School schoolTwo=new School();
		schoolTwo.setTitle("中学");
		List<String>middleList=new ArrayList<String>();
		middleList.add("华师附中");
		middleList.add("北京二中");
		schoolTwo.setDetailList(middleList);
		mSchools.add(schoolTwo);
		
		mExAdapter=new ExAdapter(mSchools, this);
		mExpandableListView.setAdapter(mExAdapter);
		//去掉系统箭头
//		mExpandableListView.setGroupIndicator(null);
	}
这个方法也不复杂,前面一半是数据填充,adapter的使用和ListView的使用方法基本一致,那么接下来的关键是 ExAdapter 的实现了,先丢出 ExAdapter 代码

package com.example.test;

import java.util.List;

import com.example.androidtexta.MainActivity;
import com.example.androidtexta.R;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
import android.widget.Toast;

public class ExAdapter extends BaseExpandableListAdapter{
    
	private List<School>mDatas;
	private Context mContext;
	
	public ExAdapter(List<School>datas,Context context){
		this.mDatas=datas;
		this.mContext=context;
	}
	
	@Override
	public int getGroupCount() {
		// TODO Auto-generated method stub
		return mDatas==null?0:mDatas.size();
	}

	@Override
	public int getChildrenCount(int groupPosition) {
		if(mDatas==null||mDatas.isEmpty()){
			return 0;
		}
		return mDatas.get(groupPosition).getDetailList()==null?0:mDatas.get(groupPosition).getDetailList().size();
	}

	@Override
	public Object getGroup(int groupPosition) {
		// TODO Auto-generated method stub
		return mDatas==null?null:mDatas.get(groupPosition);
	}

	@Override
	public Object getChild(int groupPosition, int childPosition) {
		if(mDatas==null||mDatas.isEmpty()){
			return null;
		}
		return mDatas.get(groupPosition).getDetailList()==null?null:mDatas.get(groupPosition).getDetailList().get(childPosition);
	}

	@Override
	public long getGroupId(int groupPosition) {
		// TODO Auto-generated method stub
		return mDatas==null?0:groupPosition;
	}

	@Override
	public long getChildId(int groupPosition, int childPosition) {
		if(mDatas==null||mDatas.isEmpty()){
			return 0;
		}
		return mDatas.get(groupPosition).getDetailList()==null?0:childPosition;
	}

	@Override
	public boolean hasStableIds() {
		// TODO Auto-generated method stub
		return true;
	}
	
	/**ExpandableListView 如果子条目需要响应click事件,必需返回true*/
	@Override
	public boolean isChildSelectable(int groupPosition, int childPosition) {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
		GroupHolder groupHolder;
		if(convertView==null){
			groupHolder=new GroupHolder();
			convertView=LayoutInflater.from(mContext).inflate(R.layout.adapter_group, null);
			convertView.setTag(groupHolder);
		}else{
			groupHolder=(GroupHolder) convertView.getTag();
		}
		
		groupHolder.title=(TextView) convertView.findViewById(R.id.tv_title);
		School school=mDatas.get(groupPosition);
		groupHolder.title.setText(school.getTitle());
		
		return convertView;
	}

	@Override
	public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
		ChildHolder childHolder;
		if(convertView==null){
			childHolder=new ChildHolder();
			convertView=LayoutInflater.from(mContext).inflate(R.layout.adapter_child, null);
			convertView.setTag(childHolder);
		}else{
			childHolder=(ChildHolder) convertView.getTag();
		}
		
		childHolder.detail=(TextView) convertView.findViewById(R.id.tv_detail);
		String middleMsg=mDatas.get(groupPosition).getDetailList().get(childPosition);
		childHolder.detail.setText(middleMsg);
		
		return convertView;
	}
	
	class GroupHolder{
		TextView title;
	}
	
	class ChildHolder{
		TextView detail;
	}

}

代码很长,需要注意的是 ExpandableListView 对应个 adapter 不再是 BaseAdapter 了,而是 BaseExpandableListAdapter 。虽然 adapter 变了,可是大部分方法还是差不多的,这里检些比较陌生的来讲讲

首先是  hasStableIds() ,对于此方法不是很熟,经查阅,得出的结果如下:

这样说把. 通知ListView, 你id是唯一的. 不会重复,
默认这个方法是返回false的, 需要返回true.  这样, 才能使用ListView的CHOICE_MODE_MULTIPLE, CHOICE_MODE_SINGLE, 通过getCheckedItemIds方法才能正常获取用户选中的选项的id, LZ可以试试看
这个的意思就是你的每个item中元素的id是否稳定,如果你用position当id ,那就是不稳定的,如果有自己特定的id那就是稳定的 就是干这个用的


以上是别人的解说,大意是为了保持id的稳定性,一般设为true


再看看 isChildSelectable(int groupPosition, int childPosition) 方法,他的作用是为了让 ExpandableListView 的 二级菜单响应 点击事件,返回 true 时,ExpandableListView的二级列表的点击事件会响应,返回false时,点击 ExpandableListView 的二级列表是没反应的,所以一般返回 true


ok,再来看看 ExpandableListView  的点击事件,回到 MainActivity 中 看 setListener 方法:

	private void setListener() {
		//一级点击事件
		mExpandableListView.setOnGroupClickListener(new OnGroupClickListener() {
			@Override
			public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
				boolean flag=mExpandableListView.isGroupExpanded(groupPosition);
				
				Toast.makeText(MainActivity.this, mSchools.get(groupPosition).getTitle(), 0).show();
				if(flag){
					Log.i("","一级列表收起");
				}else{
					Log.i("","一级列表展开");
				}
				return false;
			}
		});
		//二级点击事件(mExAdapter中的isChildSelectable()方法需要返回true)
		mExpandableListView.setOnChildClickListener(new OnChildClickListener() {
			@Override
			public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
				String detail=mSchools.get(groupPosition).getDetailList().get(childPosition);
				Toast.makeText(MainActivity.this, detail, 0).show();
				return false;
			}
		});
		
	}
好吧,再看瞧瞧两个点击事件都做了些什么:

注意看一级点击事件中的 flag,它是一级列表是否已经展开的判断标准,当我们自定义 下拉箭头时会用到,当然,自定义的时候,需要设置 mExpandableListView.setGroupIndicator(null);,禁用系统箭头

二级点击事件主要需要注意的就是 adapter中的 isChildSelectable 要返回true 了,


最后,附上 MainActivity  界面的代码:

package com.example.androidtexta;

import java.util.ArrayList;
import java.util.List;

import com.example.test.ExAdapter;
import com.example.test.School;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.ExpandableListView.OnGroupClickListener;
import android.widget.Toast;

public class MainActivity extends Activity{
	
	private ExpandableListView mExpandableListView;
	private List<School>mSchools;
	private ExAdapter mExAdapter;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		Log.i("","=====create====");

		initView();
		initData();
		setListener();
	}

	private void initView() {
		mExpandableListView=(ExpandableListView) findViewById(R.id.expandableListView1);
	    
	}

	private void initData() {
		mSchools=new ArrayList<School>();
		School schoolOne=new School();
		schoolOne.setTitle("大学");
		List<String>bigList=new ArrayList<String>();
		bigList.add("北京大学");
		bigList.add("武汉大学");
		bigList.add("复旦大学");
		schoolOne.setDetailList(bigList);
		mSchools.add(schoolOne);
		
		School schoolTwo=new School();
		schoolTwo.setTitle("中学");
		List<String>middleList=new ArrayList<String>();
		middleList.add("华师附中");
		middleList.add("北京二中");
		schoolTwo.setDetailList(middleList);
		mSchools.add(schoolTwo);
		
		mExAdapter=new ExAdapter(mSchools, this);
		mExpandableListView.setAdapter(mExAdapter);
		//去掉系统箭头
//		mExpandableListView.setGroupIndicator(null);
	}

	private void setListener() {
		//一级点击事件
		mExpandableListView.setOnGroupClickListener(new OnGroupClickListener() {
			@Override
			public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
				boolean flag=mExpandableListView.isGroupExpanded(groupPosition);
				
				Toast.makeText(MainActivity.this, mSchools.get(groupPosition).getTitle(), 0).show();
				if(flag){
					Log.i("","一级列表收起");
				}else{
					Log.i("","一级列表展开");
				}
				return false;
			}
		});
		//二级点击事件(mExAdapter中的isChildSelectable()方法需要返回true)
		mExpandableListView.setOnChildClickListener(new OnChildClickListener() {
			@Override
			public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
				String detail=mSchools.get(groupPosition).getDetailList().get(childPosition);
				Toast.makeText(MainActivity.this, detail, 0).show();
				return false;
			}
		});
		
	}

	@Override
	protected void onDestroy(){
		super.onDestroy();
	}

}

OK,结束!




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值