用ExpandableListView做省市二级联动
今天休息时,我在读一本书,包着书皮的缘由,项目经理不知我在读什么,遂问,你读什么书,我随口道“biancheng”。项目经理听罢,满面笑容,旋即对他一侧的一个人(也是我的同事)讲,你看人家知道在休息时间补充能量,你只知道玩手机,差距就是这样一点一点落下来的!我当时偷笑,委实只能这样了,我是在读“biancheng”,只不过该书的作者是沈从文。
言归正传,项目中需要用到ExpandableListView,自己写了一个Demo,将它记录于此。
先看看主要的XML文件:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:textSize="24sp"android:text="@string/the_two_provinces_linkage"/><!--两个自定义的expandablelistview控件--><com.example.expandablelistviewtest.ScrollExpandableListViewandroid:id="@+id/provinceList"android:layout_width="match_parent"android:layout_height="wrap_content"android:childDivider="@drawable/child_bg"/><com.example.expandablelistviewtest.ScrollExpandableListViewandroid:id="@+id/cityList"android:layout_width="match_parent"android:layout_height="wrap_content"android:visibility="gone"android:childDivider="@drawable/child_bg"/></LinearLayout></ScrollView></LinearLayout>
我在布局中使用了“ScrollView”,防止一页内容过多,手机屏幕显示不下,那么,问题就来了:ScrollView会和ExpandableListView造成冲突。所以我又自定义了一个叫做“ScrollExpandableListView”的控件,代码如下:
packagecom.example.expandablelistviewtest;importandroid.content.Context;importandroid.util.AttributeSet;importandroid.widget.ExpandableListView;publicclassScrollExpandableListViewextendsExpandableListView{publicScrollExpandableListView(Contextcontext,AttributeSetattrs){super(context,attrs);}/*在ScrollView中嵌套使用ExpandableListView,ExpandableListView只会显示一行多一点。两者进行嵌套,即会发生冲突.需要重写OnMesure,对ListView或者GridView同样适用*/@OverrideprotectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){intexpandSpec=MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);super.onMeasure(widthMeasureSpec,expandSpec);}}
同样做了一些有关省市的模拟数据:
packagecom.example.expandablelistviewtest;importjava.util.ArrayList;importjava.util.HashMap;publicclassProvinceData{privateArrayList<String>provinceGroupData;//定义省级组数据privateArrayList<ArrayList<String>>provinceChildrenData;//定义省级组中的子数据privateArrayList<String>cityGroupData;//定义市级组数据privateArrayList<ArrayList<String>>cityChildrenData;//定义市级组数据中的子数据privateHashMap<String,ArrayList<String>>provinceToCityMap;//创建省市的键值对publicArrayList<String>getProvinceGroupData(){provinceGroupData=newArrayList<String>();provinceGroupData.add("省级名称");returnprovinceGroupData;}publicArrayList<ArrayList<String>>getProvinceChildrenData(){provinceChildrenData=newArrayList<ArrayList<String>>();ArrayList<String>provinceList=newArrayList<String>();provinceList.add("北京市");provinceList.add("上海市");provinceList.add("广东省");provinceList.add("浙江省");provinceList.add("江苏省");provinceList.add("湖北省");provinceList.add("山西省");provinceList.add("河北省");provinceChildrenData.add(provinceList);returnprovinceChildrenData;}publicArrayList<String>getCityGroupData(){cityGroupData=newArrayList<String>();cityGroupData.add("市级名称");returncityGroupData;}publicArrayList<ArrayList<String>>getcityChildrenData(){cityChildrenData=newArrayList<ArrayList<String>>();ArrayList<String>beijingList=newArrayList<String>();beijingList.add("海淀区");beijingList.add("丰台区");beijingList.add("昌平区");beijingList.add("密云县");cityChildrenData.add(beijingList);ArrayList<String>shanghaiList=newArrayList<String>();shanghaiList.add("嘉定区");shanghaiList.add("浦东新区");cityChildrenData.add(shanghaiList);ArrayList<String>guangdongList=newArrayList<String>();guangdongList.add("广州市");guangdongList.add("珠海市");guangdongList.add("佛山市");guangdongList.add("中山市");cityChildrenData.add(guangdongList);ArrayList<String>zhejiangList=newArrayList<String>();zhejiangList.add("杭州市");zhejiangList.add("宁波市");zhejiangList.add("嘉兴市");cityChildrenData.add(zhejiangList);ArrayList<String>jiangsuList=newArrayList<String>();jiangsuList.add("南京市");jiangsuList.add("徐州市");jiangsuList.add("扬州市");cityChildrenData.add(jiangsuList);ArrayList<String>hubeiList=newArrayList<String>();hubeiList.add("武汉市");hubeiList.add("宜昌市");hubeiList.add("荆门市");hubeiList.add("黄冈市");cityChildrenData.add(hubeiList);ArrayList<String>shanxiList=newArrayList<String>();shanxiList.add("太原市");shanxiList.add("大同市");shanxiList.add("阳泉市");cityChildrenData.add(shanxiList);ArrayList<String>hebeiList=newArrayList<String>();hebeiList.add("石家庄市");hebeiList.add("唐山市");hebeiList.add("保定市");cityChildrenData.add(hebeiList);returncityChildrenData;}publicHashMap<String,ArrayList<String>>getProvinceAndCity(){ArrayList<ArrayList<String>>cityChildrenList=getcityChildrenData();provinceToCityMap=newHashMap<String,ArrayList<String>>();for(inti=0;i<provinceChildrenData.get(0).size();i++){provinceToCityMap.put(provinceChildrenData.get(0).get(i),cityChildrenList.get(i));}returnprovinceToCityMap;}}
接下来是主要的一个类:
packagecom.example.expandablelistviewtest;importjava.util.ArrayList;importandroid.app.Activity;importandroid.os.Bundle;importandroid.view.View;importandroid.widget.ExpandableListView;importandroid.widget.ExpandableListView.OnChildClickListener;publicclassExpandableListViewTestextendsActivity{privateScrollExpandableListViewproviceList;privateScrollExpandableListViewcityList;privateArrayList<String>provinceGroupData;//定义省级组数据privateArrayList<ArrayList<String>>provinceChildrenData;//定义省级组中的子数据privateArrayList<String>cityGroupData;//定义市级组数据privateArrayList<ArrayList<String>>cityChildrenData;//定义市级组数据中的子数据privateProvinceDataprovinceData;//定义一个两个长度的数组,存放点中条目的组下标和子下标privateint[]provinceIndex=newint[2];privateint[]cityIndex=newint[2];@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_expandable_list_view_test);provinceIndex[0]=-1;provinceIndex[1]=-1;provinceData=newProvinceData();provinceGroupData=provinceData.getProvinceGroupData();provinceChildrenData=provinceData.getProvinceChildrenData();proviceList=(ScrollExpandableListView)findViewById(R.id.provinceList);//去掉ExpandableListView默认的箭头,我的手机貌似不用这一句也没有默认的箭头,谁能告诉我怎么回事……proviceList.setGroupIndicator(null);finalScrollExpandableListAdapterprovinceAdapter=newScrollExpandableListAdapter(this,provinceGroupData,provinceChildrenData,provinceIndex);proviceList.setAdapter(provinceAdapter);cityList=(ScrollExpandableListView)findViewById(R.id.cityList);cityGroupData=provinceData.getCityGroupData();proviceList.setOnChildClickListener(newOnChildClickListener(){@OverridepublicbooleanonChildClick(ExpandableListViewparent,Viewv,intgroupPosition,intchildPosition,longid){//Expandablelistview点击子条目后收起列表proviceList.collapseGroup(groupPosition);provinceIndex[0]=groupPosition;provinceIndex[1]=childPosition;cityIndex[0]=-1;cityIndex[1]=-1;StringprovinceName=provinceChildrenData.get(0).get(childPosition);cityList.setVisibility(View.VISIBLE);cityList.setGroupIndicator(null);cityChildrenData=newArrayList<ArrayList<String>>();ArrayList<String>cityName=provinceData.getProvinceAndCity().get(provinceName);cityChildrenData.add(cityName);ScrollExpandableListAdaptercityAdapter=newScrollExpandableListAdapter(ExpandableListViewTest.this,cityGroupData,cityChildrenData,cityIndex);cityList.setAdapter(cityAdapter);cityList.setOnChildClickListener(newOnChildClickListener(){@OverridepublicbooleanonChildClick(ExpandableListViewparent,Viewv,intgroupPosition,intchildPosition,longid){cityIndex[0]=groupPosition;cityIndex[1]=childPosition;cityList.collapseGroup(groupPosition);returnfalse;}});returnfalse;}});}}
最重要的构造器:
packagecom.example.expandablelistviewtest;importjava.util.ArrayList;importandroid.content.Context;importandroid.text.TextUtils;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.ViewGroup;importandroid.widget.BaseExpandableListAdapter;importandroid.widget.CheckBox;importandroid.widget.ImageView;importandroid.widget.TextView;publicclassScrollExpandableListAdapterextendsBaseExpandableListAdapter{privateContextcontext;privateArrayList<String>groupList;privateArrayList<ArrayList<String>>childList;privateLayoutInflaterlayoutInflater;//定义一个两个长度的数组,存放点中条目的组下标和子下标privateint[]index=newint[2];privateStringgroupContent;publicScrollExpandableListAdapter(Contextcontext,ArrayList<String>groupList,ArrayList<ArrayList<String>>childList,int[]index){this.context=context;this.groupList=groupList;this.childList=childList;this.index=index;layoutInflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);}@OverridepublicObjectgetChild(intgroupPosition,intchildPosition){returnchildList.get(groupPosition).get(childPosition);}@OverridepubliclonggetChildId(intgroupPosition,intchildPosition){return0;}@OverridepublicViewgetChildView(intgroupPosition,intchildPosition,booleanisLastChild,ViewconvertView,ViewGroupparent){ChildViewHoldercHolder=newChildViewHolder();if(convertView==null){convertView=layoutInflater.inflate(R.layout.item_child,null);cHolder.childContent=(TextView)convertView.findViewById(R.id.childContent);cHolder.childCheck=(CheckBox)convertView.findViewById(R.id.check);convertView.setTag(cHolder);}else{cHolder=(ChildViewHolder)convertView.getTag();}cHolder.childContent.setText(childList.get(groupPosition).get(childPosition));if(index[0]==groupPosition&&index[1]==childPosition){cHolder.childCheck.setVisibility(View.VISIBLE);}else{cHolder.childCheck.setVisibility(View.INVISIBLE);}returnconvertView;}@OverridepublicintgetChildrenCount(intgroupPosition){returnchildList.get(groupPosition).size();}@OverridepublicObjectgetGroup(intgroupPosition){returngroupList.get(groupPosition);}@OverridepublicintgetGroupCount(){returngroupList.size();}@OverridepubliclonggetGroupId(intgroupPosition){return0;}@OverridepublicViewgetGroupView(intgroupPosition,booleanisExpanded,ViewconvertView,ViewGroupparent){GroupViewHoldergHolder=newGroupViewHolder();if(convertView==null){convertView=layoutInflater.inflate(R.layout.item_group,null);gHolder.groupName=(TextView)convertView.findViewById(R.id.groupName);gHolder.groupContent=(TextView)convertView.findViewById(R.id.groupContent);gHolder.groupPic=(ImageView)convertView.findViewById(R.id.groupPic);convertView.setTag(gHolder);}else{gHolder=(GroupViewHolder)convertView.getTag();}//首次的话用户没有选择省列表中的子项目,组内容中是没有数据的if(index[0]!=-1&&index[1]!=-1){groupContent=childList.get(index[0]).get(index[1]);}else{groupContent="";}gHolder.groupName.setText(groupList.get(groupPosition));gHolder.groupPic.setBackgroundResource(R.drawable.arrow);if(!TextUtils.isEmpty(groupContent)){gHolder.groupContent.setText(groupContent);}returnconvertView;}@OverridepublicbooleanhasStableIds(){returnfalse;}@OverridepublicbooleanisChildSelectable(intgroupPosition,intchildPosition){index[0]=groupPosition;index[1]=childPosition;//实现ChildView点击事件,必须返回truereturntrue;}privateclassGroupViewHolder{TextViewgroupName;TextViewgroupContent;ImageViewgroupPic;}privateclassChildViewHolder{TextViewchildContent;CheckBoxchildCheck;}}
组Item与子Item的布局都是自定义的,它们的XML文件分别如下:
组XML:
<?xmlversion="1.0"encoding="utf-8"?><RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#ddd"android:gravity="center"><RelativeLayoutandroid:id="@+id/layout"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingLeft="10dp"android:paddingRight="10dp"><TextViewandroid:id="@+id/groupName"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:text="@string/group_name"android:textSize="20sp"/><TextViewandroid:id="@+id/groupContent"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_toLeftOf="@+id/groupPic"android:textSize="20sp"/><ImageViewandroid:id="@id/groupPic"android:layout_width="20dp"android:layout_height="20dp"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:src="@drawable/arrow"/></RelativeLayout><Viewandroid:layout_width="match_parent"android:layout_height="1dp"android:layout_alignParentBottom="true"android:layout_below="@id/layout"android:background="#ccc"/></RelativeLayout>
子XML:
<?xmlversion="1.0"encoding="utf-8"?><RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_vertical"android:paddingLeft="10dp"android:paddingRight="10dp"><TextViewandroid:id="@+id/childContent"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_toLeftOf="@+id/check"android:text="BBB"android:textSize="20sp"/><CheckBoxandroid:id="@id/check"android:layout_width="20dp"android:layout_height="20dp"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:background="@drawable/checked"android:button="@null"android:visibility="gone"/></RelativeLayout>
兴许需要讲一下设置ExpandableListView的子Item的分割线的问题,先前用“setChildDivider(null);这个方法来着,但是会报如下空指针错误:
我还不知道这句代码应写在何处,知道的朋友请告诉一下我。
我只好写一个XML文件来代替了,如下:
<?xmlversion="1.0"encoding="utf-8"?><layer-listxmlns:android="http://schemas.android.com/apk/res/android"><item><shape><!--设置ExpandableListView的Child分割线为透明--><!--<solidandroid:color="#0000"/>--><!--设置ExpandableListView的分割线为红色--><solidandroid:color="#f00"/></shape></item></layer-list>
设置成透明即可实现没有分割线的效果,为了直观些,此处我改为了红色。
事实上就这段Demo而言,完全可以做成一个ExpandableListView的,此处用了两个,是我在项目开发中另有用途。
最后看一下效果图吧:
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。