RecycleView實現的地區選擇模塊

涼拌菜 9年前發布 | 9K 次閱讀 安卓開發 Gson Android開發 移動開發

最近在做的一個項目里,需要在用戶個人資料設置頁有選擇地區功能,看了一些開源的實現方法,大多還停留在底部彈出Dialog的形式,感覺并不友好,微信的地區選擇界面是本人比較喜歡的展示形式,地區選擇的功能應該算是一個基礎功能吧,社交類、外賣類等等APP貌似都需要用戶輸入地址,選擇地區等等,所以就想著自己做一個類似的,不足的是沒有加入定位功能,以后還有很多要補充,現在先把這一塊功能獨立出來做個demo,和大家交流學習一下。

先上圖看一下效果:

RegionSelector.gif

講一下思路:結構很簡單,點擊第一個activity的設置地區,開啟第二個activity,同時把已經選擇的地區傳值,格式為 “省份 城市 地區” (沒有引號),然后地區設置完成后setResult就可以了。地區activity選擇用RecycleView實現。

AActivity <----------------onActivityResult()
|                                        |
startActivityForResult()                 |
|                                        |
BActivity---------->setResult()---------->

布局

和使用ListView差不多,不同的是RecycleView并沒有item點擊事件,因此這個需要自己實現,這個后面會講到。ok,第一步實現item布局和ViewHolder,分析一下item需要展示的內容:首先是 地名 ,還有就是后面有沒有 已選擇 ,不要忽略item的點擊事件。

item_region_layout.png

xml布局如下:

<RelativeLayout
    android:id="@+id/item_btn" ... >

    <TextView
        android:id="@+id/item_tv" ... />

    <TextView
        android:id="@+id/checked"... />
</RelativeLayout>

ViewHolder如下:

public class RegionViewHolder extends RecyclerView.ViewHolder {
    public TextView textView;
    public TextView checked;
    public ViewGroup itemBtn;

    public RegionViewHolder(View itemView) {
        super(itemView);
        initView();
    }

    private void initView() {
        textView = (TextView) itemView.findViewById(R.id.item_tv);
        checked = (TextView) itemView.findViewById(R.id.checked);
        itemBtn = (ViewGroup) itemView.findViewById(R.id.item_btn);
    }
}

Adapter適配

我們的adapter要繼承RecyclerView.Adapter,并且實現該抽象類的幾個重要方法:

public class RegionAdapter extends RecyclerView.Adapter<RegionViewHolder> {

    private List<String> itemList;//用于存放要展示的數據列表
    private String checkedStr;//當前選中的地區
    private Context context;
    private LayoutInflater layoutInflater;
    private OnItemClickListener listener;//回調點擊事件

    public RegionAdapter(Context context) {
        this.context = context;
        layoutInflater = LayoutInflater.from(context);
    }

    /* 更新數據并展示 */
    public void setData(List<String> itemList,String checkedStr) {
        this.itemList = itemList;
        this.checkedStr = checkedStr;
        notifyDataSetChanged();
    }

    @Override
    public RegionViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new RegionViewHolder(layoutInflater.inflate(R.layout.item_region_layout,parent,false));
    }

    @Override
    public void onBindViewHolder(final RegionViewHolder holder, final int position) {
        holder.textView.setText(itemList.get(position));
        holder.checked.setVisibility(checkedStr.equals(itemList.get(position))? View.VISIBLE:View.GONE);
        holder.itemBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (listener != null)
                    listener.onItemClick(holder,position);
            }
        });
    }

    @Override
    public int getItemCount() {
        return isEmpty(itemList) ? 0 : itemList.size();
    }

    private  <D> boolean isEmpty(List<D> list) {
        return (list == null || list.isEmpty());
    }

    public void setListener(OnItemClickListener listener) {
        this.listener = listener;
    }

    public interface OnItemClickListener {
        void onItemClick(RegionViewHolder holder, int position);
    }

}

RegionActivity實現

在最開始的時,本來是想省份做一個activity,城市一個activity,然后地區一個,這樣的話代碼利用率太低,最好的辦法還是在一個activity里實現,其實就是定義了一個curPage變量,記錄用戶當前選擇到第幾步了:

三個操作階段

switch (curPage) {
            case PROVINCE://用戶選擇了某個省份
                province = itemList.get(position);
                for (Result result : result_List) {
                    if (province.equals(result.getProvince()))
                        city_List = result.getCity();
                }
                provinces.clear();
                provinces.addAll(itemList);
                itemList.clear();
                for (City city : city_List) {
                    if (this.city.equals(city.getCity()))
                        itemList.add(0,city.getCity());
                    else
                        itemList.add(city.getCity());
                }
                adapter.setData(itemList,city);
                curPage++;
                break;

            case CITY://用戶選擇了某個城市
                city = itemList.get(position);
                for (City city : city_List) {
                    if (this.city.equals(city.getCity()))
                        district_List = city.getDistrict();
                }
                cities.clear();
                cities.addAll(itemList);
                itemList.clear();
                for (District district : district_List) {
                    if (this.district.equals(district.getDistrict()))
                        itemList.add(0,district.getDistrict());
                    else
                        itemList.add(district.getDistrict());
                }
                adapter.setData(itemList,district);
                curPage++;
                break;

            case DISTRICT://用戶選擇了某個地區
                district = itemList.get(position);
                setResult(RESULT_OK,new Intent().putExtra("result"
                        ,province + " " + city + " " + district));
                finish();
                break;
        }
    }

其實代碼一眼就能看清楚,就是三個階段,到最后一個階段時就setResult把結果回傳過去,不過這里要考慮到如果用戶選擇到最后一步時,如果想退出去重新選擇城市的話,一按返回就退出activity了[捂臉/(ㄒoㄒ)/~~],所以我們還需要重寫onBackPressed:

三個返回階段

@Override
    public void onBackPressed() {
        switch (curPage) {
            case PROVINCE:
                finish();
                break;

            case CITY:
                itemList.clear();
                itemList.addAll(provinces);
                adapter.setData(itemList,province);
                curPage--;
                break;

            case DISTRICT:
                itemList.clear();
                itemList.addAll(cities);
                adapter.setData(itemList,city);
                curPage--;
                break;
        }
    }

補充一下數據的裝載,首先把json數據從raw文件夾里面讀取出來,然后格式化:

try {
    if (result_List == null) {
        Gson gson = new Gson();
        Root root = gson.fromJson(StreamUtils.get(this,R.raw.city), Root.class);
        result_List = root.getResult();
    }

    for (Result result : result_List) {
        if (province.equals(result.getProvince()))
            itemList.add(0,result.getProvince());
        else
            itemList.add(result.getProvince());
    }
    adapter.setData(itemList,province);
} catch (JsonSyntaxException e) {
    e.printStackTrace();
}

這里推薦一個實用的工具,就是json數據格式化工具: pojo在線

pojo_demo.gif

順便再推薦一個Material Design配色工具: 

materialpalette.gif

是不是非常的炫酷實用呢?有了這個還要什么設計獅( ⊙ o ⊙ )!

最后再看一下項目結構:

project_structure.png

 

來自:http://www.jianshu.com/p/ead90d9542b2

 

 本文由用戶 涼拌菜 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!