关于ListView的使用可参见一步一步学android控件(之一) —— 开始篇 ,本文主要讲ExpandableListView。
ExpandableListView是一个二级列表,每一个组(Group)可以独立的展开子项目。今天做的效果:同一时刻只有一个Group展开子项目;默认没有子项目展开;点击内容时,显示一个Toast(当前点击的Item的名字)。先看效果图:
老规矩,先看布局文件:
1、界面布局文件widget_expandable_list_view.xml , 使用一个ExpandableListView:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ExpandableListView
android:id="@+id/show_expandable_list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
><!-- android:drawSelectorOnTop="false" -->
</ExpandableListView>
</LinearLayout>
2、每一个组项的布局文件:expandable_list__group_item_view.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/expandable_list_group_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/widget_button_drawable"
android:paddingLeft="36dp"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="@color/auto_complete_font_color" />
3、组中每一个item中的布局文件expandable_child_view_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/special_name_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/auto_complete_font_color"
android:background="@drawable/widget_button_pure_color"
android:paddingTop="10dp"
android:paddingBottom="10dp" />
</LinearLayout>
4、activity——WidgetExpandableListViewActivity.java(该文所有的代码都在这里面了)
package com.xy.zt.selfdefinewieget;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
public class WidgetExpandableListViewActivity extends Activity implements
ExpandableListView.OnGroupExpandListener, ExpandableListView.OnChildClickListener {
private static HashMap<String, ArrayList<String>> mCollegeInfo = new HashMap<String, ArrayList<String>>();
private static String academies[] = {
"信息科学与技术学院", "商学院", "信息管理学院", "外国语学院", "核自院", "广播影视学院", "能源学院", "政治学院", "文法学院"
};
static {
String specialty[][] = {
{
"物流管理", "电子商务", "人力资源管理", "土地资源管理", "信息管理与信息系统", "信息与计算机科学", "软件工程",
"通信工程", "物联网工程", "数字媒体技术", "电子信息工程", "核技术与核工程", "核电子与测控工程", "核勘察和核退役工程",
"地球化学与核资源工程", "电气工程及其自动化", "机电工程",
"工业设计", "工业工程"
},
{
"会计系", "工商管理系", "经贸系"
},
{
"物流管理", "电子商务", "人力资源管理", "土地资源管理", "信息管理与信息系统", "信息与计算机科学"
},
{
"国际经济与贸易", "市场营销", "会计学", "经济学", "财务管理"
},
{
"核技术与核工程", "核电子与测控工程", "核勘察和核退役工程", "地球化学与核资源工程", "电气工程及其自动化", "机电工程",
"工业设计", "工业工程"
}, {
"播音与主持艺术", "舞蹈编导", "音乐表演", "动画", "摄影"
}, {
"石油工程"
}, {
"哲学", "法学", "管理学", "教育学"
}, {
"社会学", "公共事业管理"
}
};
String key;
ArrayList<String> value;
for (int i = 0; i < academies.length; i++) {
key = academies[i];
value = new ArrayList<String>();
for (int j = 0; j < specialty[i].length; j++) {
value.add(specialty[i][j]);
}
mCollegeInfo.put(key, value);
}
}
private ExpandableListView mExList;
private ExpandableAdapterDemo mExAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.widget_expandable_list_view);
init();
}
private void init() {
mExAdapter = new ExpandableAdapterDemo(this, mCollegeInfo, academies);
mExList = (ExpandableListView) findViewById(R.id.show_expandable_list_view);
mExList.setAdapter(mExAdapter);
mExList.setOnGroupExpandListener(this);
mExList.setOnChildClickListener(this);
}
private static class ExpandableAdapterDemo extends BaseExpandableListAdapter {
LayoutInflater mInflater;
private HashMap<String, ArrayList<String>> mData; // group content
private String[] mAcademy;
private Context mContext;
public ExpandableAdapterDemo(Context context, HashMap<String, ArrayList<String>> data,
String[] academy) {
if (context == null || data == null || academy == null)
throw new IllegalArgumentException(
"please check arguments in construct method ExpandableAdapterDemo !...");
mContext = context;
mInflater = LayoutInflater.from(mContext);
mData = data;
mAcademy = academy;
}
// private boolean isDataEmpty() {
// return mData == null || mAcademy == null || mAcademy.length == 0 ||
// mData.isEmpty();
// }
public Object getChild(int groupPos, int childPos) {
return mData.get(mAcademy[groupPos]).get(childPos);
}
public long getChildId(int groupPos, int childPos) {
return childPos;
}
public View getChildView(int groupPos, int childPos,
boolean isLastChild, View convertView, ViewGroup parent) {
ChildHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.expandable_child_view_item, null);
holder = new ChildHolder();
convertView.setTag(holder);
} else {
holder = (ChildHolder) convertView.getTag();
}
holder.mSpecial = (TextView) convertView.findViewById(R.id.special_name_text);
holder.mSpecial.setText(mData.get(mAcademy[groupPos]).get(childPos));
return convertView;
}
public int getChildrenCount(int groupPos) {
return mData.get(mAcademy[groupPos]).size();
}
public Object getGroup(int groupPosition) {
return mAcademy[groupPosition];
}
public int getGroupCount() {
return mAcademy.length;
}
public long getGroupId(int groupPosition) {
return groupPosition;
}
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
GroupHolder holder;
if (convertView == null) {
holder = new GroupHolder();
convertView = mInflater.inflate(R.layout.expandable_list__group_item_view, null);
convertView.setTag(holder);
} else {
holder = (GroupHolder) convertView.getTag();
}
holder.mAcademyName = (TextView) convertView
.findViewById(R.id.expandable_list_group_text);
holder.mAcademyName.setText(mAcademy[groupPosition]);
return convertView;
}
public boolean hasStableIds() {
return true;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
private static class GroupHolder {
public TextView mAcademyName;
}
private static class ChildHolder {
public TextView mSpecial;
}
public void onGroupExpand(int groupPos) {
int groupCount = mExList.getCount();
for (int i = 0; i < groupCount; i++) {
if (i != groupPos) {
mExList.collapseGroup(i);
}
}
}
public boolean onChildClick(ExpandableListView exList, View v, int groupPos, int childPos,
long id) {
TextView tv = (TextView) v.findViewById(R.id.special_name_text);
Toast.makeText(this, "您所选择的的专业: " + tv.getText(), Toast.LENGTH_LONG).show();
return true;
}
}
代码中首先准备好要显示的数据:
private static HashMap<String, ArrayList<String>> mCollegeInfo = new HashMap<String, ArrayList<String>>();
private static String academies[] = {
"信息科学与技术学院", "商学院", "信息管理学院", "外国语学院", "核自院", "广播影视学院", "能源学院", "政治学院", "文法学院"
};
static {
String specialty[][] = {
{
"物流管理", "电子商务", "人力资源管理", "土地资源管理", "信息管理与信息系统", "信息与计算机科学", "软件工程",
"通信工程", "物联网工程", "数字媒体技术", "电子信息工程", "核技术与核工程", "核电子与测控工程", "核勘察和核退役工程",
"地球化学与核资源工程", "电气工程及其自动化", "机电工程",
"工业设计", "工业工程"
},
{
"会计系", "工商管理系", "经贸系"
},
{
"物流管理", "电子商务", "人力资源管理", "土地资源管理", "信息管理与信息系统", "信息与计算机科学"
},
{
"国际经济与贸易", "市场营销", "会计学", "经济学", "财务管理"
},
{
"核技术与核工程", "核电子与测控工程", "核勘察和核退役工程", "地球化学与核资源工程", "电气工程及其自动化", "机电工程",
"工业设计", "工业工程"
}, {
"播音与主持艺术", "舞蹈编导", "音乐表演", "动画", "摄影"
}, {
"石油工程"
}, {
"哲学", "法学", "管理学", "教育学"
}, {
"社会学", "公共事业管理"
}
};
String key;
ArrayList<String> value;
for (int i = 0; i < academies.length; i++) {
key = academies[i];
value = new ArrayList<String>();
for (int j = 0; j < specialty[i].length; j++) {
value.add(specialty[i][j]);
}
mCollegeInfo.put(key, value);
}
}
最终的数据最后存到一个HashMap中。接下来就是初始化控件信息:
private void init() {
mExAdapter = new ExpandableAdapterDemo(this, mCollegeInfo, academies);
mExList = (ExpandableListView) findViewById(R.id.show_expandable_list_view);
mExList.setAdapter(mExAdapter);
mExList.setOnGroupExpandListener(this);
mExList.setOnChildClickListener(this);
}
上述代码中使用到了mExAdapter,其详细实现如下:
private static class ExpandableAdapterDemo extends BaseExpandableListAdapter {
LayoutInflater mInflater;
private HashMap<String, ArrayList<String>> mData; // group content
private String[] mAcademy;
private Context mContext;
public ExpandableAdapterDemo(Context context, HashMap<String, ArrayList<String>> data,
String[] academy) {
if (context == null || data == null || academy == null)
throw new IllegalArgumentException(
"please check arguments in construct method ExpandableAdapterDemo !...");
mContext = context;
mInflater = LayoutInflater.from(mContext);
mData = data;
mAcademy = academy;
}
public Object getChild(int groupPos, int childPos) {
return mData.get(mAcademy[groupPos]).get(childPos);
}
public long getChildId(int groupPos, int childPos) {
return childPos;
}
public View getChildView(int groupPos, int childPos,
boolean isLastChild, View convertView, ViewGroup parent) {
ChildHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.expandable_child_view_item, null);
holder = new ChildHolder();
convertView.setTag(holder);
} else {
holder = (ChildHolder) convertView.getTag();
}
holder.mSpecial = (TextView) convertView.findViewById(R.id.special_name_text);
holder.mSpecial.setText(mData.get(mAcademy[groupPos]).get(childPos));
return convertView;
}
public int getChildrenCount(int groupPos) {
return mData.get(mAcademy[groupPos]).size();
}
public Object getGroup(int groupPosition) {
return mAcademy[groupPosition];
}
public int getGroupCount() {
return mAcademy.length;
}
public long getGroupId(int groupPosition) {
return groupPosition;
}
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
GroupHolder holder;
if (convertView == null) {
holder = new GroupHolder();
convertView = mInflater.inflate(R.layout.expandable_list__group_item_view, null);
convertView.setTag(holder);
} else {
holder = (GroupHolder) convertView.getTag();
}
holder.mAcademyName = (TextView) convertView
.findViewById(R.id.expandable_list_group_text);
holder.mAcademyName.setText(mAcademy[groupPosition]);
return convertView;
}
public boolean hasStableIds() {
return true;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
插句题外话:写的过程中冒出一个想法,如果将每个组中Item再使用一个ListView如何? ~_~ . 有空可以试试。
整个内容就跟写ListView 的Adapter差不多了。
下述代码实现了每次点击的时候只有一个组(Group)被展开:
public void onGroupExpand(int groupPos) {
int groupCount = mExList.getCount();
for (int i = 0; i < groupCount; i++) {
if (i != groupPos) {
mExList.collapseGroup(i);
}
}
}
注意:开发中有时候在点击了Group项后才从网络上加载要显示的数据,这时将代码写到
ExpandableListView.OnGroupClickListener 中或许更好 。
对group中item的点击事件的响应ExpandableListView.OnChildClickListener,代码中点击item时显示Toast,并告知系统响应事件已经处理。
public boolean onChildClick(ExpandableListView exList, View v, int groupPos, int childPos,
long id) {
TextView tv = (TextView) v.findViewById(R.id.special_name_text);
Toast.makeText(this, "您所选择的的专业: " + tv.getText(), Toast.LENGTH_LONG).show();
return true;
}
5、在ViewData.java中添加如下内容(此部分内容可选):
public static final int EXPANDABLE_LIST_VIEW_ID = WIDGET_SCROLL_ID + 1;
public static final String EXPANDABLE_LIST_VIEW_NAME = "ExpandableListView";
private static final ViewData mExpandableListView = new ViewData(EXPANDABLE_LIST_VIEW_NAME,
EXPANDABLE_LIST_VIEW_ID);
View_Datas.add(mExpandableListView);
WidgetsAdapter的handleItemClicked中添加如下内容:
case ViewData.EXPANDABLE_LIST_VIEW_ID:
intent.setClass(mContext, WidgetExpandableListViewActivity.class);
mContext.startActivity(intent);
break;
6、在此记录下与本文无关的内容—— ListView的优化
关于ListView的优化呢,网络上也有很多内容介绍了,其目的呢就是提高ListView的效率。这里就记录下一种常用的优化方案:
1、使用一个static的类存储每个item中的View。如上述代码中
private static class GroupHolder {
public TextView mAcademyName;
}
2、getView中代码的写法
GroupHolder holder;
if (convertView == null) {
holder = new GroupHolder();
convertView = mInflater.inflate(R.layout.expandable_list__group_item_view, null);
convertView.setTag(holder);
} else {
holder = (GroupHolder) convertView.getTag();
}
... ...
... ...
return convertView;
ExpandableListView优化同理:在Adapter的getGroupView和getChildView中分别向上述步骤添加代码即可。
ListView和ExpandableListView就完了,下一个控件 GridView 。