一. 前言
1. 什么是ExpandableListView?
1 2 3 4 5 6 7
| java.lang.Object ↳android.view.View ↳android.view.ViewGroup ↳android.widget.AdapterView<T extends android.widget.Adapter> ↳android.widget.AbsListView ↳android.widget.ListView ↳android.widget.ExpandableListView
|
根据继承图来看,ExpandableListView是ListView的子类。而expandable 在英文中的意思是可扩展的,所以ExpandableListView就是一个可以扩展的、有层级的ListView。
二. 属性 & 属性
1. 指示器
1 2 3
| android:groupIndicator android:childIndicator
|
① 如果想取消默认的 gropIndicator,可以将它赋值为”@null”,即:android:groupIndicator="@null"
。
② 替换默认indicator时,我们使用了一个selector,在编写这个selector时需要特别注意,我们用的状态是 state_expanded
,这个状态在编写的时候不会自动补全,必须完全手动拼写!!
③ 默认情况下,指示器会覆盖组条目内容。为了避免这种情况,我们就需要手动的在布局文件中或者代码中将组条目向右移,以保证条目内容不被覆盖。
④ 例子
1 2 3 4 5
| <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/weixin_friend" android:state_expanded="true"/> <item android:drawable="@drawable/xiangguan"/> </selector>
|
2. 普通方法
1 2 3 4 5 6 7 8 9 10 11
| public boolean collapseGroup(int groupPos) 收起 groupPos 位置的分组
public boolean expandGroup(int groupPos) 展开 groupPos 位置的分组
public boolean isGroupExpanded(int groupPosition) 判断 groupPosition 位置的分组是否展开
public void setAdapter(ExpandableListAdapter adapter) 给 ExpandableListView 设置适配器
|
3. 监听方法
1 2 3 4 5 6 7 8 9 10 11
| public void setOnChildClickListener(OnChildClickListener onChildClickListener) 设置分组中子条目的点击监听器
public void setOnGroupClickListener(OnGroupClickListener listener) 设置分组的点击监听器
public void setOnGroupCollapseListener(OnGroupCollapseListener listener) 设置分组收起的监听器
public void setOnGroupExpandListener(OnGroupExpandListener listener) 设置分组展开的监听器
|
4. 其他的属性
1 2 3 4 5 6 7 8 9 10
| divider dividerHeight
childDivider
indicatorLeft indicatorStart indicatorRight indicatorEnd
|
三. BaseExpandableListAdapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| class MyAdapter extends BaseExpandableListAdapter {
@Override public int getGroupCount() { }
@Override public int getChildrenCount(int groupPosition) { }
@Override public Object getGroup(int groupPosition) { }
@Override public Object getChild(int groupPosition, int childPosition) { }
@Override public long getGroupId(int groupPosition) { }
@Override public long getChildId(int groupPosition, int childPosition) { }
@Override public boolean hasStableIds() { }
@Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { }
@Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { }
@Override public boolean isChildSelectable(int groupPosition, int childPosition) { } }
|
关于hasStableIds的作用
参考:hasStableIds的作用
四. 实际例子
1. 自定义的ExpandableListView包括内部类的适配器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
| public class XLExpandableListView extends ExpandableListView {
public XLExpandableListView(Context context) { super(context);
init(); }
public XLExpandableListView(Context context, AttributeSet attrs) { super(context, attrs);
init(); }
private void init() { MyAdapter adapter = new MyAdapter(); setAdapter(adapter); }
class MyAdapter extends BaseExpandableListAdapter {
@Override public int getGroupCount() { return DataUtil.getGroups().size(); }
@Override public int getChildrenCount(int groupPosition) { return DataUtil.getItems().get(groupPosition).size(); }
@Override public Object getGroup(int groupPosition) { return DataUtil.getGroups().get(groupPosition); }
@Override public Object getChild(int groupPosition, int childPosition) { return DataUtil.getItems().get(groupPosition).get(childPosition); }
@Override public long getGroupId(int groupPosition) { return groupPosition; }
@Override public long getChildId(int groupPosition, int childPosition) { return childPosition; }
@Override public boolean hasStableIds() { return false; }
@SuppressLint("InflateParams") @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { if (convertView == null){ convertView = LayoutInflater.from(getContext()).inflate(R.layout.group_layout,null); }
TextView group_name_view = convertView.findViewById(R.id.group_name); group_name_view.setText((String) getGroup(groupPosition));
return convertView; }
@SuppressLint("InflateParams") @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { if (convertView == null){ convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_layout,null); }
TextView item_name_view = convertView.findViewById(R.id.item_name); item_name_view.setText((String) getChild(groupPosition,childPosition));
return convertView; }
@Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } } }
|
2. group和item的布局
① group的布局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <?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="wrap_content" android:paddingTop="10dp" android:paddingBottom="10dp" android:background="#22666666">
<TextView android:id="@+id/group_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="组名" android:textSize="18sp" android:layout_marginStart="50dp" android:layout_centerVertical="true" />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="4/18" android:textSize="16sp" android:layout_alignParentEnd="true" android:layout_marginEnd="10dp" android:layout_centerVertical="true" />
</RelativeLayout>
|
② item的布局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| <?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="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" android:paddingTop="10dp" android:paddingBottom="10dp" >
<ImageView android:layout_width="40dp" android:layout_height="40dp" android:src="@mipmap/ic_launcher_round" android:scaleType="fitXY" android:layout_marginStart="40dp" />
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_marginStart="12dp" >
<TextView android:id="@+id/item_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="好友名" android:textStyle="bold" android:textSize="16sp" />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="凡事都有偶然的凑巧" android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
|
3. 数据源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class DataUtil {
public static List<String> getGroups(){ List<String> groups = new ArrayList<>();
groups.add("我的家人"); groups.add("我的朋友"); groups.add("黑名单");
return groups; }
public static List<List<String>> getItems(){ List<List<String>> items = new ArrayList<>();
List<String> group_1_item = new ArrayList<>(); group_1_item.add("爸爸"); group_1_item.add("妈妈"); group_1_item.add("哥哥"); items.add(group_1_item); List<String> group_2_item = new ArrayList<>(); group_2_item.add("张三"); group_2_item.add("李四"); group_2_item.add("王二麻"); items.add(group_2_item); List<String> group_3_item = new ArrayList<>(); group_3_item.add("卖茶叶"); group_3_item.add("微商"); group_3_item.add("盗号"); items.add(group_3_item);
return items; } }
|
4. 使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">
<swu.xl.expandablelistview.XLExpandableListView android:id="@+id/expand_list_view" android:layout_width="match_parent" android:layout_height="match_parent" android:groupIndicator="@drawable/indicator" />
</RelativeLayout>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
XLExpandableListView listView = findViewById(R.id.expand_list_view);
listView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() { @Override public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { Toast.makeText(MainActivity.this, DataUtil.getGroups().get(groupPosition)+"被点击了", Toast.LENGTH_SHORT).show(); return false; } });
listView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { Toast.makeText(MainActivity.this, DataUtil.getItems().get(groupPosition).get(childPosition)+"被点击了", Toast.LENGTH_SHORT).show(); return true; } });
} }
|
5. Github地址
ExpandableListView
6. 运行效果

五. 问题解决
1. 去除默认点击水波纹效果
1 2
| <item name="android:colorControlHighlight">@android:color/transparent</item>
|
六. 参考文章
ExpandableListView
安卓的ExpandableListView的使用和优化
ExpandableListView–基本使用介绍