1. 程式人生 > >Android城市選擇列表(一)——RecyclerView資料分組

Android城市選擇列表(一)——RecyclerView資料分組

地區選擇功能在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 purposes
of view recycling.
<p>The default implementation of this method returns 0, making the assumption of
a single view type for the adapter. Unlike ListView adapters, types need not
be 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城市選擇列表——RecyclerView資料分組

地區選擇功能在APP中是非常常見的,Demo主要簡單實現了快速索引選擇地區的功能,本帖圍繞此demo,介紹如何在RecyclerView中分組展示資料以及快速索引。 先上效果圖: 1.虛擬資料 建立一個類儲存一串json格式的地區資料

Android 踩坑記錄- Recyclerview的快取機制

起因上週因為業務需要,要完成一個展示優惠券資訊的列表,列表內每張券都有詳細資訊,點選詳細資訊或者右面向下的箭頭,可以展開相應優惠券的詳細資訊。展開的同時新增兩個動畫,展開的佈局需要做緩慢展開的動畫,向下展開的箭頭需要做順時針180度旋轉變成向上收縮的狀態。當時看到這覺得沒問題,一個RecyclerView就搞

Android內存優化DVM和ART原理初探

java虛擬機 劃分 cimage beef 靜態 由於 jar blank 查找 要學習Android的內存優化,首先要了解Java虛擬機,此前我用了多篇文章來介紹Java虛擬機的知識,就是為了這個系列做鋪墊。在Android開發中我們接觸的是與Java虛擬機類似的Dal

android的入門記錄

下載到本地 可能 安裝 subst 數據 工具包 一次 以及 由於 ---恢復內容開始--- 首先,這是我人生中的第一篇博客,也許嚴格意義上它並不算是一篇博客,但也代表著一些東西。 前言 我們往往在開始學習一門新的語言或者課程時會遇見各式各樣的問題,比

Android系統啟動流程解析init進程啟動過程

option 寫入 android change failed miss 通知 target sna 前言 作為“Android框架層”這個大系列中的第一個系列,我們首先要了解的是Android系統啟動流程,在這個流程中會涉及到很多重要的知識點,這個系列我們就來一一講解它們

訪問控制列表配置命令及原理

ip協議 tp服務器 tcp/ip協議 deny 管理 通信 rpc 文本 控制 訪問控制列表(一)TCP/IP協議族的傳輸層協議主要有兩個:(1)TCP傳輸控制協議(2)UDP用戶數據報協議 TCP是面向連接的、可靠的進程到進程通信的協議TCP提供全雙工服務,即數據可在同

Android項目實戰: SpannableString與SpannableStringBuilder

append() 同時 uil 註意 1.5 查看 strong 尊重 bject 原文:Android項目實戰(一): SpannableString與SpannableStringBuilder前言: 曾經在一些APP中的一些類似“幫助”&ld

小白的java學習之路 “ 選擇結構

測試 exti 邏輯運算符 main system 有一個 學習 並且 oid if選擇結構: if選擇結構是根據條件判斷之後再做處理的一種語法結構。 1.if選擇結構的語法: public class Demo{ public static void main(

Android繪制優化繪制性能分析

pro -i tco public 繼續 但是 們的 sched mda 前言 一個優秀的應用不僅僅是要有吸引人的功能和交互,同時在性能上也有很高的要求。運行Android系統的手機,雖然配置在不斷的提升,但仍舊無法和PC相比,無法做到PC那樣擁有超大的內存以及高性能的CP

Android內存優化Dalvik虛擬機和ART虛擬機對比

參考 -a 會有 font google 都是 http -s 轉換成 1.概述  Android4.4以上開始使用ART虛擬機,在此之前我們一直使用的Dalvik虛擬機,那麽為什麽Google突然換了Android運行的虛擬機呢?答案只有一個:ART虛擬機更優秀。 2.D

Android ANR分析實踐:北京×××搭建ANR是什麽、產生的原因及如何避免ANR

例如 三種 handler 線程處理 不足 線程阻塞 種類 工具 input 一、 什麽是北京×××搭建 dsluntan.com VX:17061863513ANR ANR,(Application Not Responding) 即應用程序無響應,在android應

Android TV開發總結構建一個TV app前要知道的事兒

進入 line 指南 col 遠程 引導 允許 方法 imp 原文:Android TV開發總結(一)構建一個TV app前要知道的事兒 版權聲明:我已委托“維權騎士”(rightknights.com)為我的文章進行維權行動.轉載務必轉載所

Android Native Hook技術

數組 chef protect 獲取 通過 防止 example tile ofo 原理分析 ADBI是一個著名的安卓平臺hook框架,基於 動態庫註入 與 inline hook 技術實現。該框架主要由2個模塊構成:1)hijack負責將so註入到目標進程空間,2)lib

Android開發 - 掌握ConstraintLayout傳統布局的問題

ttext 指定 面對復雜 簡單的 技術分享 改變 out jpg 並且 在傳統的Android開發中,頁面布局占用了我們很多的開發時間,而且面對復雜頁面的時候,傳統的一些布局會顯得非常復雜,每種布局都有特定的應用場景,我們通常需要各種布局結合起來使用來實現復雜的頁面。隨著

android下拉列表spinner

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_

Android註冊程式編寫之圖解程式設計

Android註冊程式編寫(一) (作者:Baron_wu 禁止轉載) 介面設計 首先進入Androidstudio建立一個空的工程: 選擇要執行的裝置: 選擇一個空的活動: 為app命名: 之後進入主介面: 點選紅筆畫中的視窗進入介面設計視窗: 介面設計視窗如下

【朝花夕拾】Android效能篇之序言及JVM

序言        筆者從事Anroid開發有些年頭了,深知掌握Anroid效能優化方面的知識的必要性,這是一個程式設計師必須修煉的內功。在面試中,它是面試官的摯愛,在工作中,它是程式碼質量的攔路虎,其重要性可見一斑。在團隊中,效能優化的工作又往往由經驗豐富的老師傅來

步學習Android TV/盒子開發

寫在前面的話: 本人做了幾年的機頂盒和Android電視上的應用開發,寫這些文章只是為了讓初次接觸大屏開發的同學能夠快速上手。 TV端因為沒有觸控操作,只有遙控操作,所以焦點處理、控制以及按鍵監聽是其主要特點。 焦點處理 設定可獲取焦點 佈局中需要設定某個控制元件可獲取焦點需要加

Android Lifecycle詳解

官方文件翻譯 使用生命週期感知元件處理生命週期 Lifecycle Event State LifecycleOwner 實現一個自定義的LifecycleOwner 生命週期感

圖文詳解如何搭建Windows的Android C++開發環境

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!