由于项目需要,实现一个二级列表,显示4s店,并且需要实现组和子项同时可以选择,并且将选择的项返回给activity。
1、首先建立一个shop实体类,
public class Shop implements Serializable {
private long id;
private String name;
private String fullName;
private String address;
private String longitude;
private String latitude;
private int shopType;
private long parentId;
private boolean isChecked = false;
private String sortLetters; // 显示数据拼音的首字母
List<Shop> ChildShops;(子店集合,即某一个Group下的所有项)
get,set方法省略...
}
2、从服务器获取数据,通过Gson转换工具,直接生成我们所需要的list<Shop>集合。
JSONArray parentItem = new JSONArray(response);// response是从服务器获取的json格式的字符串
for(int i=0;i<parentItem.length();i++){
Shop shop = new Gson().fromJson(parentItem.get(i).toString(),Shop.class);
shopList.add(shop);// 将一个个shop加入到shopList集合,用于传递到adapter.
}
3、显示数据
shopAdapter = new ShopAdapter(getApplicationContext(),list);// shopAdapter即重写adapter
接下来,我将重点讲这个adapter的重写
先来预览一下效果
4、定义group和child的视图
shop_parent_item.xml布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:background="@color/white"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="30dp"
android:layout_height="match_parent">
<ImageView
android:id="@+id/arrowRight"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/arrow_right_18"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1">
<TextView
android:id="@+id/parent_shop_name"
android:layout_width="match_parent"
android:layout_height="20dp"
android:text=""
android:textColor="@color/colorHeader"
android:textSize="14sp"/>
<TextView
android:id="@+id/parent_shop_address"
android:layout_width="match_parent"
android:layout_height="20dp"
android:text=""
android:textSize="10sp"
android:textColor="@color/gray"
android:layout_marginTop="5dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp">
<ImageView
android:id="@+id/parent_shop_add"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/shopadd"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
shop_child_item.xml定义如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="50dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="38dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="30dp">
<TextView
android:id="@+id/child_shop_type"
android:layout_width="30dp"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/gray"
android:textSize="10sp"
android:text=""/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1">
<TextView
android:id="@+id/child_shop_name"
android:layout_width="match_parent"
android:layout_height="20dp"
android:text=""
android:textColor="@color/skyblue"
android:textSize="14sp"/>
<TextView
android:id="@+id/child_shop_address"
android:layout_width="match_parent"
android:layout_height="15dp"
android:text=""
android:textSize="10sp"
android:textColor="@color/gray"
android:layout_marginTop="3dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp"
android:layout_marginLeft="10dp">
<ImageView
android:id="@+id/child_shop_add"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/shopadd"/>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/gray"
/>
</LinearLayout>
5、重写BaseExpandableListAdapter,实现想要的结果。直接上代码,注释写的很清楚:
package com.iftech.zhongdugps.trace.adapter;
/**
* Created by Tanghuosong on 2017/3/17.
*/
public class ShopAdapter extends BaseExpandableListAdapter {
private List<Shop> shopList = new ArrayList<>();
private LayoutInflater inflater;
private List<Shop> shopChecked = new ArrayList<>();
ParentViewHolder parentViewHolder;
ChildViewHolder childViewHolder;
// 构造函数,传入shops即activity需要显示的list
public ShopAdapter(Context context,List<Shop> shops){
this.shopList = shops;
this.inflater = LayoutInflater.from(context);
}
@Override
public int getChildrenCount(int groupPosition) {
return shopList.get(groupPosition).getChildShops().size();
}
@Override
public int getGroupCount() {
return shopList.size();
}
@Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
final Shop parentShop = getGroup(groupPosition);
if(convertView==null){
parentViewHolder = new ParentViewHolder();
convertView = inflater.inflate( R.layout.shop_parent_item, null);
parentViewHolder.parent_shop_name = (TextView) convertView.findViewById(R.id.parent_shop_name);
parentViewHolder.parent_shop_address = (TextView) convertView.findViewById(R.id.parent_shop_address);
parentViewHolder.parent_shop_add = (ImageView) convertView.findViewById(R.id.parent_shop_add);
parentViewHolder.arrowRight = (ImageView) convertView.findViewById(R.id.arrowRight);
convertView.setTag(parentViewHolder);
}else{
parentViewHolder = (ParentViewHolder)convertView.getTag();
}
parentViewHolder.parent_shop_add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!parentShop.isChecked()){// 判断是否已经选择,选择过的再次点击则移除
shopChecked.add(parentShop);
parentShop.setChecked(true);// 点击添加按钮时将该shop加入到集合中,方便activity获得所有已经选中的。
}else {
parentShop.setChecked(false);// 点击删除按钮,将该shop从集合中移除,保证选择的正确性。
shopChecked.remove(parentShop);
}
ShopAdapter.this.notifyDataSetChanged();// 通知adapter进行更新
}
});
// 以下这段是防止右侧的点击按钮出现混乱,做的标记
if(parentShop.isChecked()){
parentViewHolder.parent_shop_add.setImageResource(R.drawable.shopsub);// 选择过的图片显示红叉,代表可以删除
}else{
parentViewHolder.parent_shop_add.setImageResource(R.drawable.shopadd);// 未选中的图标显示绿色的加号,表示可以选择
}
if(getChildrenCount(groupPosition)==0){// 当某一个组的子项数为0时,左侧箭头隐藏
parentViewHolder.arrowRight.setVisibility(View.GONE);
}else{
parentViewHolder.arrowRight.setVisibility(View.VISIBLE);
}
parentViewHolder.parent_shop_name.setText(parentShop.getName());
parentViewHolder.parent_shop_address.setText(parentShop.getAddress());
return convertView;
}
@Override
public View getChildView(final int groupPosition,final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
final Shop childShop = getChild(groupPosition,childPosition);
if(convertView == null){
childViewHolder = new ChildViewHolder();
convertView = inflater.inflate(R.layout.shop_child_item,null);
childViewHolder.child_shop_type = (TextView) convertView.findViewById(R.id.child_shop_type);
childViewHolder.child_shop_name = (TextView) convertView.findViewById(R.id.child_shop_name);
childViewHolder.child_shop_address = (TextView) convertView.findViewById(R.id.child_shop_address);
childViewHolder.child_shop_add = (ImageView) convertView.findViewById(R.id.child_shop_add);
convertView.setTag(childViewHolder);
}else{
childViewHolder = (ChildViewHolder) convertView.getTag();
}
// 以下这是该项目特殊需求,读者可以自动忽略
if((childShop.getShopType())==2){
childViewHolder.child_shop_type.setText("二库");
}else{
childViewHolder.child_shop_type.setText("二网");
}
// 理解同parentViewHolder
childViewHolder.child_shop_add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!childShop.isChecked()){
childShop.setChecked(true);
shopChecked.add(childShop);
}else{
childShop.setChecked(false);
shopChecked.remove(childShop);
}
ShopAdapter.this.notifyDataSetChanged();
}
});
if(childShop.isChecked()){
childViewHolder.child_shop_add.setImageResource(R.drawable.shopsub);
}else{
childViewHolder.child_shop_add.setImageResource(R.drawable.shopadd);
}
childViewHolder.child_shop_name.setText(childShop.getName());
childViewHolder.child_shop_address.setText(childShop.getAddress());
return convertView;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public Shop getChild(int groupPosition, int childPosition) {
return shopList.get(groupPosition).getChildShops().get(childPosition);
}
@Override
public Shop getGroup(int groupPosition) {
return shopList.get(groupPosition);
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
@Override
public void onGroupExpanded(int groupPosition) {
super.onGroupExpanded(groupPosition);
}
@Override
public boolean hasStableIds() {
return true;
}
public List<Shop> getShopChecked() {
return shopChecked;
}
public void setShopChecked(List<Shop> shopChecked) {
this.shopChecked = shopChecked;
}
final static class ParentViewHolder{
private TextView parent_shop_name;
private TextView parent_shop_address;
private ImageView parent_shop_add;
private TextView catalog;
private ImageView arrowRight;
private LinearLayout cb_layout;
}
final static class ChildViewHolder{
private TextView child_shop_type;
private TextView child_shop_name;
private TextView child_shop_address;
private ImageView child_shop_add;
}
}
6、关于activity如何获得在adapter中选择的shop,有很多种方式,例如使用接口接听,观察者模式,而我在这里使用的最简便的方法,观察者模式(不懂观察者模式,请自行google)。
shopAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
super.onChanged();
selectShops = shopAdapter.getShopChecked();
for(Shop shop :selectShops){
Logger.d("Shop",shop.toString());
}
Logger.d("已选择项数","===================>"+selectShops.size());
}
});
每当adapter中点击了按钮,不管是删除或者添加都可以监听到改变
7、图片中的右侧的字母搜索本篇不做介绍,想了解的也可以google查看。还有一些小的欠缺,由于时间原因没来得及做完。例如左侧箭头在该group展开时换成向下的箭头,待完善后补充。