💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
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/](http://hubingforever.blog.163.com/blog/static/1710405792010538823477/) ExpandableListView的xml属性: ![](https://box.kancloud.cn/2016-03-10_56e0d9ad09cf8.jpg) 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); } } ~~~ ![](https://box.kancloud.cn/2016-03-10_56e0d9ad21287.jpg) **二,使用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); } } ~~~ ![](https://box.kancloud.cn/2016-03-10_56e0d9ad48ec5.jpg) 附上源码更方便学习: ~~~ 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); } } ~~~