之前,我们用了很大的篇幅讲解Android中的ListView的实现。主要介绍了ListView和Adapter的关系,ListView绑定EmptyView,使用自定义的Adapter实现ListView的复杂视图,以及使用ListView时的一些技巧。 在次的讲解中,介绍一下Android中二级列表的实现,二级列表的实现在Android中使用的是ExpandableListView类。 我们会通过一下具体的实例,实现一个groupView和childView都是通过自定义实现的二级列表。可能用到的ExpandableListView类中的功能并不多,只作为简单的介绍,需要深入研究的读者可以阅读Android提供的API文档。
一、示例分析
该Demo实现的效果是仿QQ客户客户端的列表效果,所有的联系人被分成几个分组,点击不同的分组可以展开对应的分组,查看组内的联系人。同时,添加点击事件,通过Toast提示用户点击的groupView和childView的对应位置,与用户进行交互。
JAVA代码如下:
001 | package com.devdiv.test.ui_test_exlistview; |
003 | import java.util.ArrayList; |
004 | import java.util.HashMap; |
005 | import java.util.List; |
008 | import android.app.Activity; |
009 | import android.content.Context; |
010 | import android.os.Bundle; |
011 | import android.view.LayoutInflater; |
012 | import android.view.View; |
013 | import android.view.ViewGroup; |
014 | import android.widget.BaseExpandableListAdapter; |
015 | import android.widget.ExpandableListView; |
016 | import android.widget.Toast; |
017 | import android.widget.ExpandableListView.OnChildClickListener; |
018 | import android.widget.ExpandableListView.OnGroupClickListener; |
019 | import android.widget.ImageView; |
020 | import android.widget.TextView; |
022 | public class UI_Test_ExListViewActivity extends Activity { |
024 | //定义字符串常量,作为group和child视图中TextView的标记 |
025 | private static final String GROUP_TEXT = 'group_text' ; |
027 | private static final String CHILD_TEXT1 = 'child_text1' ; |
028 | private static final String CHILD_TEXT2 = 'child_text1' ; |
030 | List<>> groupData = new ArrayList<>>(); |
031 | List<><>>> childData = new ArrayList<><>>>(); |
033 | MyExpandableListAdapter myExpandableListAdapter; |
034 | ExpandableListView myExpandableListView; |
036 | /** Called when the activity is first created. */ |
038 | public void onCreate(Bundle savedInstanceState) { |
039 | super .onCreate(savedInstanceState); |
040 | setContentView(R.layout.main); |
043 | //对groupData和childData中的数据,进行初始化 |
044 | for ( int i = 0 ; i <> 5 ; i++) { |
045 | Map groupMap = new HashMap(); |
046 | groupMap.put(GROUP_TEXT, 'group' +i); |
047 | groupData.add(groupMap); |
049 | List<>> childList = new ArrayList<>>(); |
050 | for ( int j = 0 ; j <> 5 ; j++) { |
051 | Map childMap = new HashMap(); |
052 | childMap.put(CHILD_TEXT1, 'child' +j); |
053 | childMap.put(CHILD_TEXT2, 'child' +j); |
054 | childList.add(childMap); |
056 | childData.add(childList); |
060 | myExpandableListAdapter = new MyExpandableListAdapter( this ); |
061 | myExpandableListView = (ExpandableListView) findViewById(R.id.exlist); |
062 | myExpandableListView.setAdapter(myExpandableListAdapter); |
064 | //去掉列表的分割线和GroupIndicator,可试验效果 |
065 | myExpandableListView.setGroupIndicator( null ); |
066 | myExpandableListView.setDivider( null ); |
068 | myExpandableListView.setOnChildClickListener( new OnChildClickListener() { |
071 | public boolean onChildClick(ExpandableListView parent, View v, |
072 | int groupPosition, int childPosition, long id) { |
073 | // TODO Auto-generated method stub |
074 | Toast.makeText(UI_Test_ExListViewActivity. this , 'group' + groupPosition + 'child' + childPosition, Toast.LENGTH_SHORT).show(); |
079 | myExpandableListView.setOnGroupClickListener( new OnGroupClickListener() { |
082 | public boolean onGroupClick(ExpandableListView parent, View v, |
083 | int groupPosition, long id) { |
084 | // TODO Auto-generated method stub |
085 | Toast.makeText(UI_Test_ExListViewActivity. this , 'group' + groupPosition, Toast.LENGTH_SHORT).show(); |
089 | * True if the click was handled(官方文档) |
099 | class MyExpandableListAdapter extends BaseExpandableListAdapter { |
101 | UI_Test_ExListViewActivity instanceActivity; |
104 | public MyExpandableListAdapter(UI_Test_ExListViewActivity instanseActivity) { |
106 | this .instanceActivity = instanseActivity; |
110 | public Object getChild( int groupPosition, int childPosition) { |
111 | // TODO Auto-generated method stub |
112 | return childData.get(groupPosition).get(childPosition).get(CHILD_TEXT1).toString(); |
116 | public long getChildId( int groupPosition, int childPosition) { |
117 | // TODO Auto-generated method stub |
118 | return childPosition; |
122 | public View getChildView( final int groupPosition, final int childPosition, |
123 | boolean isLastChild, View convertView, ViewGroup parent) { |
124 | // TODO Auto-generated method stub |
126 | View view = convertView; |
130 | LayoutInflater mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
131 | view = mInflater.inflate(R.layout.child_view, null ); |
134 | ImageView childImageView = (ImageView) view.findViewById(R.id.child_header); |
135 | if (childPosition% 2 == 0 ) { |
136 | childImageView.setImageResource(R.drawable.profile_hi_icon_normal); |
138 | childImageView.setImageResource(R.drawable.child_image); |
141 | TextView childTextView1 = (TextView) view.findViewById(R.id.child_text1); |
142 | childTextView1.setText(getChild(groupPosition, childPosition).toString()); |
144 | TextView childTextView2 = (TextView) view.findViewById(R.id.child_text2); |
145 | childTextView2.setText(getChild(groupPosition, childPosition).toString()); |
147 | // LinearLayout childLinearLayout = (LinearLayout) view.findViewById(R.id.linearlayout_child); |
148 | // childLinearLayout.setOnClickListener(new OnClickListener() { |
151 | // public void onClick(View v) { |
152 | // // TODO Auto-generated method stub |
154 | // Toast.makeText(UI_Test_ExListViewActivity.this, 'test!!!!!!', Toast.LENGTH_SHORT); |
155 | // Toast.makeText(UI_Test_ExListViewActivity.this, 'click child,groupPosition='+groupPosition+' childPosition='+childPosition, Toast.LENGTH_SHORT); |
163 | public int getChildrenCount( int groupPosition) { |
164 | // TODO Auto-generated method stub |
165 | return childData.get(groupPosition).size(); |
169 | public Object getGroup( int groupPosition) { |
170 | // TODO Auto-generated method stub |
171 | return groupData.get(groupPosition).get(GROUP_TEXT).toString(); |
175 | public int getGroupCount() { |
176 | // TODO Auto-generated method stub |
177 | return groupData.size(); |
181 | public long getGroupId( int groupPosition) { |
182 | // TODO Auto-generated method stub |
183 | return groupPosition; |
187 | public View getGroupView( int groupPosition, boolean isExpanded, |
188 | View convertView, ViewGroup parent) { |
189 | // TODO Auto-generated method stub |
191 | View view = convertView; |
193 | LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
194 | view = inflater.inflate(R.layout.group_view, null ); |
198 | TextView groupTextView = (TextView) view.findViewById(R.id.group_text); |
199 | groupTextView.setText(getGroup(groupPosition).toString()); |
202 | ImageView groupImageView = (ImageView) view.findViewById(R.id.group_icon); |
204 | //通过isExpanded,可以判断当前group是否处于展开的状态 |
206 | groupImageView.setBackgroundResource(R.drawable.btn_browser2); |
208 | groupImageView.setBackgroundResource(R.drawable.btn_browser); |
212 | // final int position = groupPosition; |
214 | // LinearLayout groupLinearLayout = (LinearLayout) view.findViewById(R.id.linearlayout_group); |
215 | // groupLinearLayout.setOnClickListener(new OnClickListener() { |
218 | // public void onClick(View v) { |
219 | // // TODO Auto-generated method stub |
221 | // myExpandableListView.setSelected(true); |
222 | // myExpandableListView.setFocusable(true); |
223 | // myExpandableListView.requestFocusFromTouch(); |
224 | // myExpandableListView.requestFocus(position); |
225 | // myExpandableListView.setSelection(position); |
227 | // if(myExpandableListView.isGroupExpanded(position)) |
228 | // myExpandableListView.collapseGroup(position); |
230 | // myExpandableListView.expandGroup(position); |
232 | // // TODO Auto-generated method stub |
233 | // Toast.makeText(UI_Test_ExListViewActivity.this, 'click group'+position, Toast.LENGTH_SHORT).show(); |
238 | //返回view,也就是convertView |
243 | public boolean hasStableIds() { |
244 | // TODO Auto-generated method stub |
249 | public boolean isChildSelectable( int groupPosition, int childPosition) { |
250 | // TODO Auto-generated method stub |
二级列表中有两个数据源,GroupView使用的List<>>类型ChildView使用的List<><>>>类型。 代码如下:
1 | List<>> groupData = new ArrayList<>>(); |
2 | List<><>>> childData = new ArrayList<><>>>(); |
在onCreate()方法中对groupData和childData进行了初始化,并初始化了myExpandableListView,然后把它绑定到myExpandableListView。 代码如下:
2 | myExpandableListAdapter = new MyExpandableListAdapter( this ); |
3 | myExpandableListView = (ExpandableListView) findViewById(R.id.exlist); |
4 | myExpandableListView.setAdapter(myExpandableListAdapter); |
Demo中使用了继承BaseExpandableListView类的是定义Adapter——MyExpandableListAdapter,并且实现了BaseExpandableListView中的必须要实现的方法,列举如下:
01 | public Object getChild( int groupPosition, int childPosition) |
03 | public long getChildId( int groupPosition, int childPosition) |
05 | public View getChildView( final int groupPosition, final int childPosition, |
06 | boolean isLastChild, View convertView, ViewGroup parent) |
08 | public int getChildrenCount( int groupPosition) |
10 | public Object getGroup( int groupPosition) |
12 | public int getGroupCount() |
14 | public long getGroupId( int groupPosition) |
16 | public View getGroupView( int groupPosition, boolean isExpanded, |
17 | View convertView, ViewGroup parent) |
19 | public boolean hasStableIds() |
21 | public boolean isChildSelectable( int groupPosition, int childPosition) |
其中最重要的是getGroupView()和getChildView()两个方法,这两个方法分别用来返回groupView和childView的视图,也就是最终ExpandableListView中显示的Item。Demo中在这两个方法中分别解析了group_view.xml和child_view.xml布局文件,然后根据groupPosition和childPosition分别填充groupData和childData中对应的数据,最后通过return view返回给系统。布局文件的内容不再给出,读者可以下载demo代码查看。 解析布局文件的代码如下:
1 | LayoutInflater mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
2 | view = mInflater.inflate(R.layout.child_view, null ); |
3 | LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
4 | view = inflater.inflate(R.layout.group_view, null ); |
最后为myExpandableListView绑定监听器,当用户点击时,显示Toast提示。 代码如下:
01 | myExpandableListView.setOnChildClickListener( new OnChildClickListener() { |
04 | public boolean onChildClick(ExpandableListView parent, View v, |
05 | int groupPosition, int childPosition, long id) { |
06 | // TODO Auto-generated method stub |
07 | Toast.makeText(UI_Test_ExListViewActivity. this , 'group' + groupPosition + 'child' + childPosition, Toast.LENGTH_SHORT).show(); |
12 | myExpandableListView.setOnGroupClickListener( new OnGroupClickListener() { |
15 | public boolean onGroupClick(ExpandableListView parent, View v, |
16 | int groupPosition, long id) { |
17 | // TODO Auto-generated method stub |
18 | Toast.makeText(UI_Test_ExListViewActivity. this , 'group' + groupPosition, Toast.LENGTH_SHORT).show(); |
22 | * True if the click was handled(官方文档) |
为了是显示效果更好看需要取消Item之间的分割线,取消group的标志 :
1 | //去掉列表的分割线和GroupIndicator,可试验效果 |
2 | myExpandableListView.setGroupIndicator( null ); |
3 | myExpandableListView.setDivider( null ); |
二、效果展示
图1 Demo运行效果1
图2 Demo运行效果1
Demo源代码下载:
|