Android城市选择列表(一)——RecyclerView数据分组

来源:互联网 发布:linux ipython 编辑:程序博客网 时间:2024/06/13 09:48

地区选择功能在APP中是非常常见的,Demo主要简单实现了快速索引选择地区的功能,本帖围绕此demo,介绍如何在RecyclerView中分组展示数据以及快速索引。

先上效果图:

这里写图片描述

1.虚拟数据

创建一个类保存一串json格式的地区数据

/** * Created by kun on 2016/10/26. * 模拟数据 */public class Data {    public static final String citiesJson = "{\"datas\":[{\"alifName\":\"C\",\"addressList\":[{\"id\":37,\"name\":\"潮州\"}]},{\"alifName\":\"D\",\"addressList\":[{\"id\":20,\"name\":\"东莞\"}]},{\"alifName\":\"F\",\"addressList\":[{\"id\":21,\"name\":\"佛山\"}]},{\"alifName\":\"G\",\"addressList\":[{\"id\":5,\"name\":\"广州\"}]},{\"alifName\":\"H\",\"addressList\":[{\"id\":29,\"name\":\"惠州\"},{\"id\":32,\"name\":\"河源\"},{\"id\":33,\"name\":\"河源\"}]},{\"alifName\":\"J\",\"addressList\":[{\"id\":25,\"name\":\"江门\"},{\"id\":38,\"name\":\"揭阳\"}]},{\"alifName\":\"M\",\"addressList\":[{\"id\":27,\"name\":\"茂名\"},{\"id\":30,\"name\":\"梅州\"}]},{\"alifName\":\"Q\",\"addressList\":[{\"id\":7,\"name\":\"泉州\"},{\"id\":35,\"name\":\"清远\"}]},{\"alifName\":\"S\",\"addressList\":[{\"id\":6,\"name\":\"深圳\"},{\"id\":22,\"name\":\"韶关\"},{\"id\":24,\"name\":\"汕头\"},{\"id\":31,\"name\":\"汕尾\"}]},{\"alifName\":\"Y\",\"addressList\":[{\"id\":34,\"name\":\"阳江\"},{\"id\":39,\"name\":\"云浮\"}]},{\"alifName\":\"Z\",\"addressList\":[{\"id\":23,\"name\":\"珠海\"},{\"id\":26,\"name\":\"湛江\"},{\"id\":28,\"name\":\"肇庆\"},{\"id\":36,\"name\":\"中山\"}]}]}";}

格式如下

{    "datas":[        {            "alifName":"C",            "addressList":[                {                    "id":37,                    "name":"潮州"                }            ]        }      ]}

2.MainActivity

首先看一下布局文件,很简单,就一个RecyclerView。

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#f1f6f9">    <android.support.v7.widget.RecyclerView        android:id="@+id/recyclerView"        android:layout_width="match_parent"        android:layout_height="match_parent"/></RelativeLayout>

接着在MainActivity中初始化数据

 private void initView() {        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);        LinearLayoutManager layoutManager = new LinearLayoutManager(this);        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);        recyclerView.setLayoutManager(layoutManager);        Gson gson = new Gson();        CitiesBean citiesBean = gson.fromJson(Data.citiesJson, CitiesBean.class);        adapter = new CitiesAdapter(this,citiesBean.getDatas());        recyclerView.setAdapter(adapter);    }

这里主要给RecyclerView设置了垂直的线性布局管理者,接着封装本地的地区数据,然后创建CitiesAdapter,最后设置给RecyclerView。 数据的分组主要是交由Adapter来处理的,因此重点还是在CitiesAdapter中。

3.CitiesAdapter

a.首先CitiesAdapter需要继承RecyclerView.Adapter

public class CitiesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{}

b.接着我们要确定Adapter的ItemCount。

这里写图片描述

结合上图,在这里我把搜索、当前位置、热门城市做为一个Item,这里的数据是写死的。因此ItemCount至少是1。而每个字母以及地区都要单独占据应该Item。所以在获取ItemCount的代码如下:

 //获取数据的数量    @Override    public int getItemCount() {        if (datas == null) return 1;//用于显示头部搜索、定位地区、热门地区        int childCount = datas.size();//字母的数量        for (int i = 0; i < datas.size(); i++) {            childCount += datas.get(i).getAddressList().size();//地区的数量        }        return childCount + 1;    }

c.对Item的视图进行分类——实现getItemViewType()

获取到Item的数量后,我们要实现getItemViewType()方法。这是方法是实现分组的关键,先看官方API的介绍:

Return the view type of the item at <code>position</code> for the purposesof view recycling.<p>The default implementation of this method returns 0, making the assumption ofa single view type for the adapter. Unlike ListView adapters, types need notbe contiguous. Consider using id resources to uniquely identify item view types.

可以大致了解到该方法默认是返回0,而返回的参数主要是对应postion的Item身份资源唯一标识,用于View进行创建或回收的时候标识Item的视图类型。简单地说我们可以在这个方法中对每个position对应的Item进行视图类型标识,在onCreateViewHolder中就能根据图类型标识区分显示的是头部搜索内容、字母或者地区名。

这里我们有三种视图类型,分别为头部搜索(包含了当前和热门)、组名(字母)以及地区名。因此我们定义三个常量来代表对应的类型。

 private final int HEAD = 0;    private final int WORD = 1;    private final int CITY = 2;

接着是getItemViewType的具体实现

    @Override    public int getItemViewType(int position) {        int count = 0;        if(position==count) return HEAD;//下标为0的固定显示头部布局。        for(int i = 0; i < cities.size(); i++){            count++;            if(position==count){                return WORD;            }            List<CitiesBean.DatasBean.AddressListBean> addressList = cities.get(i).getAddressList();            for(int j =0;j<addressList.size();j++){                count++;                if(position==count){                    return CITY;                }            }        }        return super.getItemViewType(position);    }

从代码中我们可以看到,如果下标为0,则返回HEAD。接着是显示一个分组。从cities中取出第一个分组,此时下标为1时,需要先显示第一个分组的字母,所以返回WORD,接着遍历第一个分组中的地区,返回CITY。以此类推。这里我们就能标识好position对应的Item显示的视图。

d.定义ViewHodler

定义三种视图类型对应的ViewHodler

    public static class HeadViewHolder extends RecyclerView.ViewHolder {        public HeadViewHolder(View view) {            super(view);        }    }    public static class WordViewHolder extends RecyclerView.ViewHolder {        TextView textWord;        public WordViewHolder(View view) {            super(view);            textWord = (TextView) view.findViewById(R.id.textWord);        }    }    public static class CityViewHolder extends RecyclerView.ViewHolder {        TextView textCity;        public CityViewHolder(View view) {            super(view);            textCity = (TextView) view.findViewById(R.id.textCity);        }    }

e.创建视图——实现onCreateViewHolder方法

@Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {        if (viewType == TOP) {            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_index_select_city_top, viewGroup, false);            return new TopViewHolder(view);        } else if (viewType == TITLE) {            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_select_gradute_institution_word, viewGroup, false);            return new WordViewHolder(view);        } else {            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_commen_textview, viewGroup, false);            return new CityItemViewHolder(view);        }    }

在这里可以看到方法中返回了一个viewType参数,这个参数其实就是在getItemViewType中返回的。因此我们可以根据viewType返回对应ViewHolder。

d.进行数据绑定——实现onBindViewHolder()

 @Override    public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) {        if (position == 0) {            topViewHolder = (TopViewHolder) viewHolder;            initTopViewHolder(topViewHolder);        } else {            int count = 0;            for (int i = 0; i < datas.size(); i++) {                count += 1;                if (position == count) {                    WordViewHolder wordViewHolder = (WordViewHolder) viewHolder;                    wordViewHolder.textWord.setText(datas.get(i).getAlifName());                } else {                    List<AddressListResult.CollectionBean.DatasBean.AddressListBean> addressList = datas.get(i).getAddressList();                    for (int j = 0; j < addressList.size(); j++) {                        count += 1;                        if (position == count) {                            final AddressListResult.CollectionBean.DatasBean.AddressListBean addressListBean = addressList.get(j);                            CityItemViewHolder schoolViewHolder = (CityItemViewHolder) viewHolder;                            schoolViewHolder.textSchoolName.setText(addressListBean.getName());                            schoolViewHolder.itemView.setOnClickListener(new View.OnClickListener() {                                @Override                                public void onClick(View v) {                                    EventMessage message = new EventMessage();                                    message.setType(24);                                    message.setData(addressListBean.getName());                                    EventBus.getDefault().post(message);                                    ((Activity) context).finish();                                }                            });                        }                    }                }            }        }    }

在这里,主要还是通过position与count进行对比,区分当前Item对应的视图类型。其实也可以通过viewHolder.getItemViewType()的方法获取到当前的视图类型。但是基于当前的需求场景,通过第一种方法会比较方便,因此这里采用了position与count进行对比。

到这里分组的功能就实现了,效果如下:

这里写图片描述

欢迎继续阅读下一篇

Android地区选择列表(二)——快速索引

0 0
原创粉丝点击