首页 > 代码库 > Android:ExpandableListView使用

Android:ExpandableListView使用

前言

目前回到了工作岗位,第一件事情就是ExpandListView的优化。这里简单的用一个Demo介绍一下ExpandableListView的使用。

简单介绍一下Demo实现的功能,主要是继承BaseExpandableListAdapter来自定义adapter呈现ExpandableListView数据:
  • 每个child item有一个TextView和一个ImageView删除标识。
  • 当点击一个child item,弹出Toast提示。
  • child item可以通过点击删除图标来删除。
  • 每次展开特定group时,其他group自动收缩。
Demo效果展示:




Android实现

创建一个新的Android项目,我将其命名为expandtutorial。

XML布局文件

expandtutorial项目总共需要三个xml布局文件,分别是activity_main.xml, child_item.xml, group_item.xml。

activity_main.xml

这个是用来布局ExpandableListView的,内容如下:

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

    <ExpandableListView
        android:id="@+id/expandable_list_view_id"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </ExpandableListView>

</RelativeLayout>

group_item.xml

这是用来定义父列表的样式,由一个TextView和一个ImageView构成

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="#ffffff"
    android:orientation="horizontal"
    android:gravity="center_vertical">
    
    <TextView 
        android:id="@+id/group_text"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginLeft="16dp"
        android:textColor="#808080"
        android:textSize="16sp"
        android:gravity="center_vertical"
        android:layout_alignParentLeft="true"
        android:text="@string/app_name"/>
    
    <ImageView 
        android:id="@+id/group_indicator"
        android:src=http://www.mamicode.com/"@drawable/ic_guide_listview_down">

child_item.xml

这是用来定义孩子列表的样式

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/child_item_id"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp" >

    <TextView
        android:id="@+id/child_item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:paddingLeft="25dp" />

    <ImageView
        android:id="@+id/child_delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:contentDescription="@null"
        android:src=http://www.mamicode.com/"@drawable/delete" />>

自定义Adapter

自定义adapter是继承自BaseExpandableListAdapter,有几个需要注意的地方:
  • 使用静态内部类标识父item和子item的weidget,因为这些控件的id是相同的,这样可以节省掉每次findViewById的时间。
  • 重写(override)isChildSelectable方法,返回true,表示子item是可以点击的。
package com.example.expandtutorial;

import java.util.ArrayList;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class CustomerAdapter extends BaseExpandableListAdapter{
	private ArrayList<ParentObj> datas;
	private Context context;
	
	public CustomerAdapter(ArrayList<ParentObj> datas, Context context) {
		super();
		this.datas = datas;
		this.context = context;
	}

	@Override
	public int getGroupCount() {
		return datas.size();
	}

	@Override
	public int getChildrenCount(int groupPosition) {
		return datas.get(groupPosition).getChilds().size();
	}

	@Override
	public Object getGroup(int groupPosition) {
		return datas.get(groupPosition);
	}

	@Override
	public Object getChild(int groupPosition, int childPosition) {
		return datas.get(groupPosition).getChilds().get(childPosition);
	}

	@Override
	public long getGroupId(int groupPosition) {
		return groupPosition;
	}

	@Override
	public long getChildId(int groupPosition, int childPosition) {
		return childPosition;
	}

	@Override
	// 是否有稳定的id,跟刷新顺序有关
	public boolean hasStableIds() {
		return false;
	}

	@Override
	public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
		ParentViewHolder pviewHolder;
		
		if (convertView == null) {
			convertView = LayoutInflater.from(context).inflate(R.layout.group_item, parent, false);
			pviewHolder = new ParentViewHolder();
			pviewHolder.pTextView = (TextView) convertView.findViewById(R.id.group_text);
			pviewHolder.pImageView = (ImageView) convertView.findViewById(R.id.group_indicator);
			convertView.setTag(pviewHolder);
		}
		
		pviewHolder = (ParentViewHolder)convertView.getTag();
		pviewHolder.pTextView.setTypeface(null, Typeface.BOLD);
		pviewHolder.pTextView.setText(datas.get(groupPosition).getpName());
		
		if (isExpanded) {
			pviewHolder.pImageView.setImageResource(R.drawable.ic_guide_listview_up);
		} else {
			pviewHolder.pImageView.setImageResource(R.drawable.ic_guide_listview_down);
		}
		
		return convertView;
	}

	@Override
	public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView,
			ViewGroup parent) {
		ChildViewHolder cViewHolder;
		
		if (convertView == null) {
			convertView = LayoutInflater.from(context).inflate(R.layout.child_item, parent, false);
			cViewHolder = new ChildViewHolder();
			cViewHolder.cTextView = (TextView)convertView.findViewById(R.id.child_item);
			cViewHolder.cImageView = (ImageView) convertView.findViewById(R.id.child_delete);
			convertView.setTag(cViewHolder);
		}
		
		cViewHolder = (ChildViewHolder)convertView.getTag();
		cViewHolder.cTextView.setText(datas.get(groupPosition).getChilds().get(childPosition).getcName());
		
		final int gPosition = groupPosition;
		final int cPosition = childPosition;
		cViewHolder.cImageView.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				AlertDialog.Builder builder = new AlertDialog.Builder(context);
				builder.setMessage("Do you want to remove?");
				builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
						datas.get(gPosition).getChilds().remove(cPosition);
						notifyDataSetChanged();
					}
				});
				builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.cancel();
					}
				});
				AlertDialog alertDialog = builder.create();
				alertDialog.show();
			}
		});
		
		return convertView;
	}

	@Override
	public boolean isChildSelectable(int groupPosition, int childPosition) {
		return true;
	}
	
	static class ParentViewHolder {
		TextView pTextView;
		ImageView pImageView;
	}
	
	static class ChildViewHolder {
		TextView cTextView;
		ImageView cImageView;
	}
}

Activity

我们的主Activity,用来呈现UI效果,这里主要有两个地方需要注意:
  • ExpandableListView需要和自定义adapter进行绑定,通过setAdapter方法。
  • 默认ExpandableListView带了一个指示箭头,我们自定义布局是不需要这个指示箭头的,可以使用expandableListView.setGroupIndicator(null);方法将其去掉。
  • 设置setOnGroupExpandListener,当展开一个特定的group时,关闭其他group。
  • 设置setOnChildClickListener,监听孩子点击事件。
package com.example.expandtutorial;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.ExpandableListView.OnGroupExpandListener;
import android.widget.Toast;

public class MainActivity extends Activity {
	private ExpandableListView expandableListView;
	private CustomerAdapter customerAdapter;
	private ArrayList<ParentObj> listData = http://www.mamicode.com/new ArrayList();>

源码

我将源码上传到CSDN,大家可以免费下载,欢迎跟帖讨论。源码地址:http://download.csdn.net/detail/zinss26914/7532205