Android 中关于ExpandableListView的简单使用,以一个demo为例,比较简单,主要用于理解一些概念性的知识。仅作为学习笔记。
1、定义:可扩展的ListView。
public class ExpandableListView extends ListView {
......
}
继承自ListView,因此基本使用方法同ListView:
(1)需要自定义一个继承自BaseExpandableListAdapter的Adapter;当然包括相关的布局等。
(2)注册监听事件;
由于该例子很简单,直接查看代码及注释,更清晰的显示常用方法的作用,在此不再详述。
2、基本用法:
//主界面布局:
<Button
android:id="@+id/expandBtn"
android:textSize="18sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/expandable_des"
/>
<ExpandableListView
android:layout_marginTop="10dp"
android:id="@+id/expandableListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/bg_default"
android:groupIndicator="@null"
android:visibility="gone"
></ExpandableListView>
<!--
android:groupIndicator="@null" 去掉系统自带的展开图标
-->
1 //自定义适配器ExpandAdapter.java
2 public class ExpandAdapter extends BaseExpandableListAdapter {
3 private final String TAG = "ExpandAdapter";
4
5 private Context mContext;
6 private LayoutInflater layoutInflater;
7
8 private String[] groupNames = new String[]
9 {"C++","JAVA","Android","HTML"};
10
11 // private Drawable leftDrawable; //具体看本文末尾补充部分
12 private int arrowUpId,arrowDownId;
13
14 public ExpandAdapter(Context context) {
15 // TODO Auto-generated constructor stub
16 mContext = context;
17 layoutInflater = LayoutInflater.from(mContext);
18
19 arrowUpId = R.drawable.arrow_up;
20 arrowDownId = R.drawable.arrow_down;
21
22 // leftDrawable = context.getDrawable(R.drawable.ic_launcher);
23 // leftDrawable.setBounds(0, 0, leftDrawable.getMinimumWidth(), leftDrawable.getMinimumHeight());
24 }
25
26 @Override
27 public Object getChild(int arg0, int arg1) {
28 // TODO Auto-generated method stub
29 return null;
30 }
31
32 @Override
33 public long getChildId(int arg0, int arg1) {
34 // TODO Auto-generated method stub
35 return arg1;
36 }
37
38 @Override
39 public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View childView,
40 ViewGroup parent) { //子项布局
41 // TODO Auto-generated method stub
42 ChildHolder childHolder;
43
44 if(childView == null){
45 childView = layoutInflater.inflate(R.layout.child_view, null);
46 childHolder = new ChildHolder();
47 childHolder.child_content = (TextView) childView.findViewById(R.id.child_content);
48 childView.setTag(childHolder);
49 }else{
50 childHolder = (ChildHolder) childView.getTag();
51 }
52
53 // Log.d(TAG, "getChildView groupPos: " + groupPosition + " childPos: " + childPosition);
54
55 // if(groupPosition < groupNames.length){
56 // groupHolder.name_type.setText(groupNames[groupPosition]);
57 // }
58
59 // if(childPosition % 2 == 0){
60 // childHolder.child_content.setText("使用 drawableLeft getChildView getChildView getChildView getChildView");
61 // childHolder.child_content.setCompoundDrawables(leftDrawable, null, null, null);
62 // }
63
64 return childView;
65 }
66
67 @Override
68 public int getChildrenCount(int arg0) { //子项总数
69 return 5;
70 }
71
72 @Override
73 public Object getGroup(int arg0) {
74 return groupNames[arg0];
75 }
76
77 @Override
78 public int getGroupCount() { //一级列表项数
79 return groupNames.length;
80 }
81
82 @Override
83 public long getGroupId(int groupPosition) {
84 return groupPosition;
85 }
86
87 @Override
88 public View getGroupView(int groupPosition, boolean isExpand, View convertView, ViewGroup parent) {//一级列表项
89 // TODO Auto-generated method stub
90 GroupHolder groupHolder;
91
92 if(convertView == null){
93 convertView = layoutInflater.inflate(R.layout.grounp_view, null);
94 groupHolder = new GroupHolder();
95 groupHolder.img_type = (ImageView) convertView.findViewById(R.id.img_type);
96 groupHolder.name_type = (TextView) convertView.findViewById(R.id.name_type);
97 groupHolder.img_arrow = (ImageView) convertView.findViewById(R.id.img_arrow);
98 convertView.setTag(groupHolder);
99 }else{
100 groupHolder = (GroupHolder) convertView.getTag();
101 }
102
103 if(isExpand){
104 // groupHolder.img_arrow.setImageResource(R.drawable.arrow_up);
105 groupHolder.img_arrow.setImageResource(arrowUpId);
106 }else{
107 // groupHolder.img_arrow.setImageResource(R.drawable.arrow_down);
108 groupHolder.img_arrow.setImageResource(arrowDownId);
109 }
110
111 Log.i(TAG, "getGroupView groupPosition: " + groupPosition + " isExpand: " + isExpand);
112
113 if(groupPosition < groupNames.length){
114 groupHolder.name_type.setText(groupNames[groupPosition]);
115 }
116
117 return convertView;
118 }
119
120 @Override
121 public boolean hasStableIds() {
122 return false;
123 }
124
125 //为了使子项响应点击事件,此处必须返回true!!!!!!!!!!!!!!!!!!!!!!!!!!!
126 @Override
127 public boolean isChildSelectable(int arg0, int arg1) {
128 // TODO Auto-generated method stub
129 return true;
130 }
131
132 class GroupHolder{
133 ImageView img_type,img_arrow;
134 TextView name_type;
135 }
136 class ChildHolder{
137 TextView child_content;
138 }
139
140 }
1 ExpandableListViewActivity中的基本使用:
2
3 expandableListView = (ExpandableListView) findViewById(R.id.expandableListView);
4
5 expandAdapter = new ExpandAdapter(this);
6 expandableListView.setAdapter(expandAdapter);
7
8 //注册监听事件:
9 private void initExpandableListener(){
10 expandableListView.setOnGroupClickListener(new OnGroupClickListener() {
11 @Override
12 public boolean onGroupClick(ExpandableListView expandableListView, View arg1, int groupPosition,
13 long arg3) { //组(一级列表)点击事件 默认return false;若设为true,表示点击列表不会展开
14 // TODO Auto-generated method stub
15 Log.i(TAG, "onGroupClick " + groupPosition);
16
17 return false;
18 }
19 });
20 expandableListView.setOnGroupCollapseListener(new OnGroupCollapseListener() {
21 @Override
22 public void onGroupCollapse(int groupPosition) { //折叠
23 // TODO Auto-generated method stub
24 Log.i(TAG, "onGroupCollapse " + groupPosition);
25
26 }
27 });
28 expandableListView.setOnGroupExpandListener(new OnGroupExpandListener() {
29 @Override
30 public void onGroupExpand(int groupPosition) { //展开 若需要展开某项,其他项关闭,可在该处理方法中写入相应逻辑
31 // TODO Auto-generated method stub
32 Log.i(TAG, "onGroupExpand " + groupPosition);
33
34 }
35 });
36
37
38 //Child
39 expandableListView.setOnChildClickListener(new OnChildClickListener() {
40
41 @Override
42 public boolean onChildClick(ExpandableListView arg0, View arg1, int groupPosition,
43 int childPosition, long arg4) {
44 // TODO Auto-generated method stub
45 Log.i(TAG, "onChildClick " + groupPosition + " " + childPosition);
46
47 return false;
48 }
49 });
50
51
52 //添加一个按钮,用于测试expandGroup(int groupPos, boolean animate)中的animate不同值的显示效果.
53 Button expandBtn = (Button) findViewById(R.id.expandBtn);
54 expandBtn.setOnClickListener(new OnClickListener() {
55 @Override
56 public void onClick(View v) {
57 // TODO Auto-generated method stub
58 expandableListView.expandGroup(3, false); //展开时,是否执行滑动过程; 建议在测试时,选择展开后列表能够超出屏幕的,更容易看到两者不同
59 //看源码,发现为true时执行了方法smoothScrollToPosition(position, boundPosition)
60 //在默认情况下,点击group选项,系统也会执行上述smoothScrollToPosition方法.
61
62 }
63 });
64
65 }
函数expandGroup(int groupPos, boolean animate)的执行效果:

默认界面 animate=false animate=true
3、注意事项:
a.写布局时,为了去掉系统自带的展开图标(上下箭头),需设置ExpandableListView的android:groupIndicator="@null"
b.可展开列表的适配器一般自定义,并继承自BaseExpandableListAdapter。当然,对于一些简单的数据或布局,可直接使用SimpleExpandableListAdapter或SimpleCursorTreeAdapter。
c.可以让Activity继承ExpandableListActivity,这样在Activity即可重写相关点击事件的方法.因为ExpandableListActivity实现了这些方法的接口。
d.若让子项响应点击事件,必须在ExpandAdapter中设置isChildSelectable()方法返回true。
4、补充:
上述demo中的子项布局很简单,因为是简单的测试,所以只在布局中定义了一个TextView,图片使用了android:drawableLeft,在ExpandAdapter中可以看到还保留有在代码中设置图片的代码(注释的部分line),以下就总结以下用法:
//子项布局child_view.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:paddingTop="10dp"
android:paddingBottom="10dp"
>
<TextView
android:id="@+id/child_content"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginStart="5dp"
android:drawableLeft="@drawable/ic_launcher"
android:ellipsize="end"
android:gravity="center_vertical"
android:text="child name"
android:textSize="20sp"
android:singleLine="true"
android:maxLength="30"
/>
</LinearLayout>
总结:android中,若图标+文字确定的,则可使用TextView一个控件来实现,利用drawableLeft/drawableTop...等。但,若图标不确定,需要在代码中动态设置,则建议分开写,ImageView + TextView 。
因,在代码中设置图标很麻烦,需要以下三步:
(1) leftDrawable(获取Drawable对象)
(2) leftDrawable.setBounds(0, 0, leftDrawable.getMinimumWidth(), leftDrawable.getMinimumHeight());
(3) childHolder.child_content.setCompoundDrawables(leftDrawable, null, null, null);