ExpandableListView是ListView的子类,他在ListView上进行了扩展,它把列表项分成了几组,每组里包含了多个列表项
ExpandableListView的列表项是由ExpandableListAdapter提供的,实现ExpandableListAdapter三种常用方式,常用的ExpandableListAdapter子类如下:
1,扩展BaseExpandableListAdapter实现ExpandableListAdapter
2,使用SimpleExpandableListAdapter将 两个List集合包装成ExpandableListAdapter
3,使用SimpleCursorTreeAdapter将Cursor中的数据包装成SimpleCursorTreeAdapter
ExpandableListAdapter及其子类的继承关系类图看这篇文章讲的比较好,看懂了:http://hubingforever.blog.163.com/blog/static/1710405792010538823477/
ExpandableListView的xml属性:
android:childDivider 指定个组内各子列表项之间的分隔条
android:childIndicator 显示子列表项旁边的Drawble对象
android:groupIndicator 显示组列表项旁边的Drawble对象
ExpandableListView是android中可以实现下拉list的一个控件,是一个垂直滚动的心事两个级别列表项手风琴试图,列表项是来自ExpandableListViewaAdapter,组可以单独展开。
重要方法:
<span style="font-size:24px;">expandGroup (int groupPos) ;//在分组列表视图中 展开一组,
setSelectedGroup (int groupPosition) ;//设置选择指定的组。
setSelectedChild (int groupPosition, int childPosition, boolean shouldExpandGroup);//设置选择指定的子项。
getPackedPositionGroup (long packedPosition);//返回所选择的组
getPackedPositionForChild (int groupPosition, int childPosition) ;//返回所选择的子项
getPackedPositionType (long packedPosition);//返回所选择项的类型(Child,Group)
isGroupExpanded (int groupPosition);//判断此组是否展开</span>
<span style="font-size:24px;">expandableListView.setDivider();这个是设定每个Group之间的分割线。
expandableListView.setGroupIndicator();这个是设定每个Group之前的那个图标。
expandableListView.collapseGroup(int group); 将第group组收起</span>
一,使用扩展BaseExpandableListAdapter来提供数据源
扩展BaseExpandableListAdapter需要重写11个方法:
* getGroupCount(),返回包含组列表的数量
* getChildrenCount(int groupPosition),返回包含组列表的数量
*
* getGroup(int groupPosition),返回组列表的对象
* getChild(int groupPosition, int childPosition),返回组列表下的子列表对象
*
* getGroupId(int groupPosition),返回组列表Id
* getChildId(int groupPosition, int childPosition),返回祖列表的子列表的Id
* 下面两个属性很重要!
* getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent),该方法决定每个组选项的外观、
* getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent),该方法决定每个子选项的外观、
*isChildSelectable(int groupPosition,
int childPosition):如果child添加监听事件,则要返回true
Main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--ExpandableListView组件
android:childDivider 指定个组内各子列表项之间的分隔条
android:childIndicator 显示子列表项旁边的Drawble对象
android:groupIndicator 显示组列表项旁边的Drawble对象
-->
<ExpandableListView
android:id="@+id/expandableListView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:childDivider="#f0f"
>
</ExpandableListView>
</LinearLayout>
MainActivity.java
package com.hust.expandablelistview;
import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.LayoutParams;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BaseExpandableListAdapter bela=new BaseExpandableListAdapter(){
/*自动实现这10个方法
* getGroupCount(),返回包含组列表的数量
* getChildrenCount(int groupPosition),返回包含组列表的数量
*
* getGroup(int groupPosition),返回组列表的对象
* getChild(int groupPosition, int childPosition),返回组列表下的子列表对象
*
* getGroupId(int groupPosition),返回组列表Id
* getChildId(int groupPosition, int childPosition),返回祖列表的子列表的Id
*
* getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent),该方法决定每个组选项的外观、
* getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent),该方法决定每个子选项的外观、
*
*
* */
int[] logos=new int[]{
R.drawable.p,R.drawable.z,R.drawable.t
};
//组列表的数量
private String[] armTypes=new String[]{"我的好友","高中同学","大学同学"};
//组列表下的子列表项,可扩展的ExpandableListView是个二维数组
private String[][] arms=new String[][]{
{"狂战士","龙骑士","黑暗圣堂","电兵"},
{"张娜","李四","赵龙","钱爽"},
{"王燕","刘涛","张坦克","汪明城"}
};
//返回包含组列表的数量
@Override
public int getGroupCount() {
// TODO Auto-generated method stub
return armTypes.length;
}
//返回组位置下的子列表项的数量
@Override
public int getChildrenCount(int groupPosition) {
// TODO Auto-generated method stub
return arms[groupPosition].length;
}
//返回组列表的对象
@Override
public Object getGroup(int groupPosition) {
// TODO Auto-generated method stub
return armTypes[groupPosition];
}
//返回组列表下的子列表对象
@Override
public Object getChild(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return arms[groupPosition][childPosition];
}
//返回组列表Id
@Override
public long getGroupId(int groupPosition) {
// TODO Auto-generated method stub
return groupPosition;
}
//返回祖列表的子列表的Id
@Override
public long getChildId(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return childPosition;
}
@Override
public boolean hasStableIds() {
// TODO Auto-generated method stub
return true;
}
//该方法决定每个组选项的外观、这里这定义组列表布局,也可以用xml文件
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
LinearLayout ll=new LinearLayout(MainActivity.this);
ll.setOrientation(0);
ImageView logo=new ImageView(MainActivity.this);
logo.setImageResource(logos[groupPosition]);
TextView textview=getTextView();
textview.setText(getGroup(groupPosition).toString());
ll.addView(logo);
ll.addView(textview);
return ll;
}
//设置TextView的参数
private TextView getTextView() {
// TODO Auto-generated method stub
AbsListView.LayoutParams lp=new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,64);
TextView textview=new TextView(MainActivity.this);
textview.setLayoutParams(lp);//设置布局参数,android:layout_Width="match_parent",android:layout_Height="64"
textview.setGravity(Gravity.CENTER_VERTICAL|Gravity.LEFT);//android:gravity="CENTER_VERTICAL|LEFT"
textview.setPadding(36, 0, 0, 0);
textview.setTextSize(16); //android:textsize="20dp"
return textview;
}
//该方法决定每个子选项的外观
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
TextView text=getTextView();
text.setText(getChild(groupPosition,childPosition).toString());
return text;
}
@Override
public boolean isChildSelectable(int groupPosition,
int childPosition) {
// TODO Auto-generated method stub
return true;
}
};
ExpandableListView expandablelistview=(ExpandableListView) findViewById(R.id.expandableListView1);
//设置adapter
expandablelistview.setAdapter(bela);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
二,使用SimpleExpandableListAdapter显示ExpandableListView
SimpleExpandableListAdapter adapter = new SimpleExpandableListAdapter(
this, gruops, R.drawable.expandablelistview_groups, new String[]{"group"}, new int[]{R.id.textGroup},
childs, R.drawable.expandablelistview_child, new String[]{"child"}, new int[]{R.id.textChild}
);
* 参数1.上下文对象Context
* 参数2.一级条目目录集合
* 参数3.一级条目对应的布局文件 (expandablelistview_groups.xml文件
* 参数4.fromto,就是map中的key,指定要显示的对象
* 参数5.与参数4对应,指定要显示在groups中的id
* 参数6.二级条目目录集合
* 参数7.二级条目对应的布局文件
* 参数9.与参数8对应,指定要显示在childs中的id
1,定义一个主界面expandablelistview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ExpandableListView
android:id ="@+id/expandableListView"
android:layout_width ="fill_parent"
android:layout_height ="wrap_content"
>
</ExpandableListView>
</LinearLayout>
2.在res/drawable目录下创建样式文件expandablelistview_groups.xml该界面是组界面:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textGroup"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="40px"
android:paddingTop="6px"
android:paddingBottom="6px"
android:textSize="15sp"
android:text="No data"
>
</TextView>
</LinearLayout>
3.在res/drawable目录下创建样式文件expandablelistview_child.xml;是子控件,直接显示列表内容
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textChild"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="60px"
android:paddingTop="10px"
android:paddingBottom="10px"
android:textSize="20sp"
android:text="No Data" />
</LinearLayout>
ExpandableListViewDemo_two.java
public class ExpandableListViewDemo_two extends Activity {
/** Called when the activity is first created. */
private ExpandableListView expandableListView_one;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.expandablelistview);
expandableListView_one =(ExpandableListView)findViewById(R.id.expandableListView);
//创建二个一级条目标题
Map<String, String> title_1 = new HashMap<String, String>();
Map<String, String> title_2 = new HashMap<String, String>();
title_1.put("group", "移动开发");
title_2.put("group", "Web开发");
//创建一级条目容器
List<Map<String, String>> gruops = new ArrayList<Map<String,String>>();
gruops.add(title_1);
gruops.add(title_2);
//创建二级条目内容
//内容一
Map<String, String> content_1 = new HashMap<String, String>();
Map<String, String> content_2 = new HashMap<String, String>();
content_1.put("child", "ANDROID");
content_2.put("child", "IOS");
List<Map<String, String>> childs_1 = new ArrayList<Map<String,String>>();
childs_1.add(content_1);
childs_1.add(content_2);
//内容二
Map<String, String> content_3 = new HashMap<String, String>();
Map<String, String> content_4 = new HashMap<String, String>();
Map<String, String> content_5 = new HashMap<String, String>();
content_3.put("child", "jsp");
content_4.put("child", "servlet");
content_5.put("child", "page");
List<Map<String, String>> childs_2 = new ArrayList<Map<String,String>>();
childs_2.add(content_3);
childs_2.add(content_4);
childs_2.add(content_5);
//存放两个内容, 以便显示在列表中
List<List<Map<String, String>>> childs = new ArrayList<List<Map<String,String>>>();
childs.add(childs_1);
childs.add(childs_2);
//创建ExpandableList的Adapter容器
/**
* 使用SimpleExpandableListAdapter显示ExpandableListView
* 参数1.上下文对象Context
* 参数2.一级条目目录集合
* 参数3.一级条目对应的布局文件 (expandablelistview_groups.xml文件
* 参数4.fromto,就是map中的key,指定要显示的对象
* 参数5.与参数4对应,指定要显示在groups中的id
* 参数6.二级条目目录集合
* 参数7.二级条目对应的布局文件
* 参数9.与参数8对应,指定要显示在childs中的id
/ SimpleExpandableListAdapter adapter = new SimpleExpandableListAdapter(
this, gruops, R.drawable.expandablelistview_groups, new String[]{"group"}, new int[]{R.id.textGroup},
childs, R.drawable.expandablelistview_child, new String[]{"child"}, new int[]{R.id.textChild}
);
//加入列表
expandableListView_one.setAdapter(adapter);
expandableListView_one.setOnChildClickListener(listener);
}
private OnChildClickListener listener =new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
// TODO Auto-generated method stub
toast("点击了");
return false;
}
};
private void toast(String str) {
Toast.makeText(this, str, Toast.LENGTH_LONG).show();
}
}
上面的样式也可以使用系统的自带的样式如下:
android.R.layout.simple_expandable_list_item_1,//层显示样式 ,系统自定义
android.R.layout.simple_expandable_list_item_2,
ExpandableListActivity直接继承了Activity。
1,继承ExpandableListActivity
2,定义好内容ExpandableListAdapter,扩展BaseExpandableListAdapter和SimpleExpandableListAdapter都可以
3,setListAdapter的方法添加adapter
package com.example.expandablelistactivity;
import android.app.ExpandableListActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class MainActivity extends ExpandableListActivity//继承ExpandableListActivity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//无需布局文件
//自定义扩展BaseExpandableListAdapter
ExpandableListAdapter adapter = new BaseExpandableListAdapter()
{
int[] logos = new int[]
{
R.drawable.p,
R.drawable.z,
R.drawable.t
};
//组列表的数量
private String[] armTypes=new String[]{"我的好友","高中同学","大学同学"};
//组列表下的子列表项,可扩展的ExpandableListView是个二维数组
private String[][] arms=new String[][]{
{"狂战士","龙骑士","黑暗圣堂","电兵"},
{"张娜","李四","赵龙","钱爽"},
{"王燕","刘涛","张坦克","汪明城"}
};
//获取指定组位置、指定子列表项处的子列表项数据
@Override
public Object getChild(int groupPosition, int childPosition)
{
return arms[groupPosition][childPosition];
}
@Override
public long getChildId(int groupPosition, int childPosition)
{
return childPosition;
}
@Override
public int getChildrenCount(int groupPosition)
{
return arms[groupPosition].length;
}
private TextView getTextView()
{
AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, 64);
TextView textView = new TextView(MainActivity.this);
textView.setLayoutParams(lp);
textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
textView.setPadding(36, 0, 0, 0);
textView.setTextSize(16);
return textView;
}
//该方法决定每个子选项的外观
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent)
{
TextView textView = getTextView();
textView.setText(getChild(groupPosition, childPosition).toString());
return textView;
}
//获取指定组位置处的组数据
@Override
public Object getGroup(int groupPosition)
{
return armTypes[groupPosition];
}
@Override
public int getGroupCount()
{
return armTypes.length;
}
@Override
public long getGroupId(int groupPosition)
{
return groupPosition;
}
//该方法决定每个组选项的外观
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent)
{
LinearLayout ll = new LinearLayout(MainActivity.this);
ll.setOrientation(0);
ImageView logo = new ImageView(MainActivity.this);
logo.setImageResource(logos[groupPosition]);
ll.addView(logo);
TextView textView = getTextView();
textView.setText(getGroup(groupPosition).toString());
ll.addView(textView);
return ll;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition)
{
return true;
}
@Override
public boolean hasStableIds()
{
return true;
}
};
// 设置该窗口显示列表
setListAdapter(adapter);
}
}
附上源码更方便学习:
public class ExpandableListActivity extends Activity implements
OnCreateContextMenuListener,
ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener,
ExpandableListView.OnGroupExpandListener {
ExpandableListAdapter mAdapter;
ExpandableListView mList;
boolean mFinishedStart = false;
/**
* Override this to populate the context menu when an item is long pressed. menuInfo
* will contain an {@link android.widget.ExpandableListView.ExpandableListContextMenuInfo}
* whose packedPosition is a packed position
* that should be used with {@link ExpandableListView#getPackedPositionType(long)} and
* the other similar methods.
* <p>
* {@inheritDoc}
*/
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
}
/**
* Override this for receiving callbacks when a child has been clicked.
* <p>
* {@inheritDoc}
*/
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
int childPosition, long id) {
return false;
}
/**
* Override this for receiving callbacks when a group has been collapsed.
*/
public void onGroupCollapse(int groupPosition) {
}
/**
* Override this for receiving callbacks when a group has been expanded.
*/
public void onGroupExpand(int groupPosition) {
}
/**
* Ensures the expandable list view has been created before Activity restores all
* of the view states.
*
*@see Activity#onRestoreInstanceState(Bundle)
*/
@Override
protected void onRestoreInstanceState(Bundle state) {
ensureList();
super.onRestoreInstanceState(state);
}
/**
* Updates the screen state (current list and other views) when the
* content changes.
*
* @see Activity#onContentChanged()
*/
@Override
public void onContentChanged() {
super.onContentChanged();
View emptyView = findViewById(com.android.internal.R.id.empty);
mList = (ExpandableListView)findViewById(com.android.internal.R.id.list);
if (mList == null) {
throw new RuntimeException(
"Your content must have a ExpandableListView whose id attribute is " +
"'android.R.id.list'");
}
if (emptyView != null) {
mList.setEmptyView(emptyView);
}
mList.setOnChildClickListener(this);
mList.setOnGroupExpandListener(this);
mList.setOnGroupCollapseListener(this);
if (mFinishedStart) {
setListAdapter(mAdapter);
}
mFinishedStart = true;
}
/**
* Provide the adapter for the expandable list.
*/
public void setListAdapter(ExpandableListAdapter adapter) {
synchronized (this) {
ensureList();
mAdapter = adapter;
mList.setAdapter(adapter);
}
}
/**
* Get the activity's expandable list view widget. This can be used to get the selection,
* set the selection, and many other useful functions.
*
* @see ExpandableListView
*/
public ExpandableListView getExpandableListView() {
ensureList();
return mList;
}
/**
* Get the ExpandableListAdapter associated with this activity's
* ExpandableListView.
*/
public ExpandableListAdapter getExpandableListAdapter() {
return mAdapter;
}
private void ensureList() {
if (mList != null) {
return;
}
setContentView(com.android.internal.R.layout.expandable_list_content);
}
/**
* Gets the ID of the currently selected group or child.
*
* @return The ID of the currently selected group or child.
*/
public long getSelectedId() {
return mList.getSelectedId();
}
/**
* Gets the position (in packed position representation) of the currently
* selected group or child. Use
* {@link ExpandableListView#getPackedPositionType},
* {@link ExpandableListView#getPackedPositionGroup}, and
* {@link ExpandableListView#getPackedPositionChild} to unpack the returned
* packed position.
*
* @return A packed position representation containing the currently
* selected group or child's position and type.
*/
public long getSelectedPosition() {
return mList.getSelectedPosition();
}
/**
* Sets the selection to the specified child. If the child is in a collapsed
* group, the group will only be expanded and child subsequently selected if
* shouldExpandGroup is set to true, otherwise the method will return false.
*
* @param groupPosition The position of the group that contains the child.
* @param childPosition The position of the child within the group.
* @param shouldExpandGroup Whether the child's group should be expanded if
* it is collapsed.
* @return Whether the selection was successfully set on the child.
*/
public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) {
return mList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup);
}
/**
* Sets the selection to the specified group.
* @param groupPosition The position of the group that should be selected.
*/
public void setSelectedGroup(int groupPosition) {
mList.setSelectedGroup(groupPosition);
}
}