博主声明:
转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。
本文首发于此 博主:威威喵 | 博客主页:https://blog.csdn.net/smile_running
在 Android 开发中,一个 App 通常会有这种的需求,就是在一个列表内部在嵌套一个列表,下面我们来看看效果图就知道了。
首先呢,我们要准备一个处理 ExpandableListView 的数据的适配器,只需继承BaseExpandableListAdapter 重写里面的方法即可。下面我们来看看这个代码吧:
/**
* @author xww
* @desciption : ExpandableListView 适配器
* @date 2019/10/24
* @time 16:10
*/
public class CitySelectAdapter extends BaseExpandableListAdapter {
private Context mContext;
private List<CitySelectBean> mDataBeans;
public CitySelectAdapter(Context context, List<CitySelectBean> citySelectBeans) {
this.mContext = context;
this.mDataBeans = citySelectBeans;
}
@Override
public int getGroupCount() {
return mDataBeans.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return mDataBeans.get(groupPosition).getCity().size();
}
@Override
public Object getGroup(int groupPosition) {
return mDataBeans.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return mDataBeans.get(groupPosition).getCity().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 true;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
GroupHolder holder = null;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.exp_list_city_select_province, null);
holder = new GroupHolder(convertView);
convertView.setTag(holder);
} else {
holder = (GroupHolder) convertView.getTag();
}
holder.tvProvince.setText(mDataBeans.get(groupPosition).getProvince());
return convertView;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ChildHolder holder = null;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.exp_list_city_select_city, null);
holder = new ChildHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ChildHolder) convertView.getTag();
}
holder.tvCity.setText(mDataBeans.get(groupPosition).getCity().get(childPosition));
return convertView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public class GroupHolder {
TextView tvProvince;
GroupHolder(View itemView) {
tvProvince = itemView.findViewById(R.id.exp_list_province);
}
}
public class ChildHolder {
TextView tvCity;
ChildHolder(View itemView) {
tvCity = itemView.findViewById(R.id.exp_list_city);
}
}
}
看这个适配器给我们提供的方法,就很容易知道我们要传入的一个数据模型,下面我就拿省份、城市来举个例子。我们的一级列表是省份,二级列表里面是各个省的城市。它的数据模型是这样样子的:
/**
* @author xww
* @desciption :
* @date 2019/10/24
* @time 16:08
*/
public class CitySelectBean {
private String province;
private List<String> city;
public CitySelectBean(String province, List<String> city) {
this.province = province;
this.city = city;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public List<String> getCity() {
return city;
}
public void setCity(List<String> city) {
this.city = city;
}
}
由于提供的数据比较简单,那么适配器的 item 布局就放一个 TextView 即可,但是这里要分清楚,一共有两个 item 布局,一个是省份的,一个是城市的,代码如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/exp_list_province"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutDirection="ltr"
android:padding="8dp" />
RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/exp_list_city"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layoutDirection="ltr"
android:paddingLeft="24dp"
android:paddingBottom="8dp" />
RelativeLayout>
那么到此,我们的适配器以及布局文件就准备好了,然后是我们的 Activity 的布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorWhite"
android:orientation="vertical">
<TextView
style="@style/TopTitleBarStyle"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="选择城市" />
<ExpandableListView
android:id="@+id/explv_city_select"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutDirection="rtl" />
LinearLayout>
最后,就是我们如何添加数据了, Activity 的代码如下:
/**
* @author xww
* @desciption :
* @date 2019/10/24
* @time 16:01
*/
public class CitySelectActivity extends BasePermissionActivity {
private ExpandableListView explvCity;
private CitySelectAdapter mCitySelectAdapter;
private List<CitySelectBean> mCitySelectBeans;
@Override
protected void initLayout(@Nullable Bundle savedInstanceState) {
super.initLayout(savedInstanceState);
setContentView(R.layout.activity_city_select);
}
@Override
protected void initViews() {
super.initViews();
explvCity = $(R.id.explv_city_select);
}
@Override
protected void initData() {
super.initData();
mCitySelectBeans = new ArrayList<>();
mCitySelectBeans.add(new CitySelectBean("福建省", Arrays.asList("宁德", "福州", "厦门", "漳州", "泉州")));
mCitySelectBeans.add(new CitySelectBean("广东省", Arrays.asList("汕头", "东菀", "深圳", "广州")));
mCitySelectBeans.add(new CitySelectBean("浙江省", Arrays.asList("温州", "杭州", "绍兴", "嘉兴")));
mCitySelectAdapter = new CitySelectAdapter(this, mCitySelectBeans);
explvCity.setAdapter(mCitySelectAdapter);
}
}
这里有一个属性介绍一下
android:layoutDirection="rtl"
这个属性是把如下图的那个箭头设置到右边,因为在左边时会被文字给挡住了,显得不好看。
下面是 ExpandableListView 的 Item 点击事件,这个肯定会使用得到,代码也很简单,如下:
// 设置一级列表点击事件
explvCity.setOnGroupClickListener((parent, v, groupPosition, id) -> {
String province = mCitySelectBeans.get(groupPosition).getProvince();
return false;
});
// 设置二级列表点击事件
explvCity.setOnChildClickListener((parent, v, groupPosition, childPosition, id) -> {
String city = mCitySelectBeans.get(groupPosition).getCity().get(childPosition);
return false;
});
还有会遇到二级菜单是默认收起来的问题,如果你需要让 ExpandableListView 的二级菜单每一个都是展开的效果,可以这样做,代码如下:
int count = explvCity.getCount(); //这里一定要这样写
for (int i = 0; i < count; i++) {
explvCity.expandGroup(i);
}
如果你要这样写的话,它会抛出下标越界异常:
for (int i = 0; i < explvCity.getCount(); i++) {
explvCity.expandGroup(i);
}