簡單好用的RecyclerView適配器

前言

給大家推薦個(gè)好用RecyclerView適配器,也就是在百籃應(yīng)用里用到的適配器指黎。為了大家學(xué)習(xí)方便朋凉,這里簡單的寫下如何使用這個(gè)適配器,不做代碼具體的分析醋安,有興趣的可以自己看下源碼杂彭。當(dāng)然用過類似的BRAVH可能會(huì)覺得已經(jīng)都這么好的工具了為何還有使用本文的適配器。我覺得有2個(gè)優(yōu)點(diǎn):

  1. 相比BRAVH更輕量吓揪∏椎。看過源碼就知道,一共用了20多個(gè)類就做到了與BRAVH基本一致的主要功能柠辞。這樣會(huì)減少應(yīng)用的體積與負(fù)擔(dān)团秽。
  2. 里面注釋比較詳細(xì),同時(shí)也因?yàn)轭惾绻雽W(xué)習(xí)的話叭首,更容易學(xué)習(xí)與理解习勤。

當(dāng)然功能自然也比BRAVH少了很多但是它更偏向于適配器本省的職責(zé)。廢話少說焙格⊥急希看看如何使用吧!


使用

image

可以看到這么復(fù)雜的效果都是用這個(gè)適配器做出來的

  • 單條目

XML布局:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <com.zhxu.recyclerview.pullrefresh.PullToRefreshView
        android:id="@+id/pull"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </com.zhxu.recyclerview.pullrefresh.PullToRefreshView>


</LinearLayout>

代碼:


 
·
   //添加數(shù)據(jù)
        for (int i = 0; i < 20; i++) {
            strList.add("我是普通的條目" + i);
        }
        rv.setLayoutManager(new LinearLayoutManager(this));
        DataAdapter adapter = new DataAdapter(this);
        adapter.addDataAll(strList);//加載數(shù)據(jù)給適配器
        mPullToRefreshView.setListener(new PullToRefreshView.OnRefreshListener() {
            @Override
            public void onRefresh() {
                //上拉監(jiān)聽
                Toast.makeText(Main2Activity.this, "上拉", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onLoadMore() {
                //下拉監(jiān)聽
                Toast.makeText(Main2Activity.this, "下拉", Toast.LENGTH_SHORT).show();
            }
        });
        adapter.setOnItemClickListener(new MultiItemTypeAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, RecyclerView.ViewHolder holder, Object o, int position) {
                //停止上拉或下拉loading狀態(tài)
                mPullToRefreshView.onFinishLoading();
            }

            @Override
            public boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, Object o, int position) {
                //長按觸發(fā)上拉刷新
                mPullToRefreshView.onAutoRefresh();
                return true;
            }
        });
        rv.setAdapter(adapter);
    }

    //CommonAdapter  是普通單一條目的父類  泛型決定賦值的數(shù)據(jù)類型
    public class DataAdapter extends CommonAdapter<String> {

        public DataAdapter(Context context) {
            //加載RecyclerView item布局
            super(context, R.layout.item_normal);
        }

        @Override
        protected void convert(ViewHolder holder, String s, int position) {
            //第一個(gè)參數(shù)是item中的布局控件id 第二個(gè)參數(shù)是要給指定控件賦值
            holder.setText(R.id.tv, s);
        }
    }
    

代碼較多但是非常簡單眷唉,里面我加的注解已經(jīng)非常全了予颤。相信到家都能理解。PullToRefreshView是實(shí)現(xiàn)上下拉刷新冬阳。
單條目適配器使用首先addDataAll()數(shù)據(jù)蛤虐。然后單條目適配器要繼承CommonAdapter泛型傳入數(shù)據(jù)的類型,我們加入的數(shù)據(jù)是String所以泛型為String摩泪,上面我們給所有item加入監(jiān)聽,當(dāng)然也可以給每個(gè)item中的任意控件添加監(jiān)聽劫谅,如下:

image.png

這里指截取了一部分见坑,里面還有很多方法嚷掠,大家可以自己測試下。這里我就不過多介紹了荞驴。其他種類適配器holder中這些方法同樣適用不皆。下面就不再提了。
效果圖:

2323F.gif
  • 多條目

先來看下效果圖:

clipboard.png

代碼

·
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);

        rv = (RecyclerView) findViewById(R.id.rv);
        userList.add(new User("張三1", 0));
        userList.add(new User("張三2", 0));
        userList.add(new User("張三3", 1));
        userList.add(new User("張三4", 0));
        userList.add(new User("張三5", 0));
        userList.add(new User("張三6", 1));
        userList.add(new User("張三7", 0));
        userList.add(new User("張三8", 0));
        userList.add(new User("張三9", 1));
        userList.add(new User("張三10", 1));
        userList.add(new User("張三11", 0));

        rv.setLayoutManager(new LinearLayoutManager(this));
        UserAdapter adapter = new UserAdapter(this, userList);
        rv.setAdapter(adapter);

    }

    //MultiItemTypeAdapter  多條目Adapter的父類
    private class UserAdapter extends MultiItemTypeAdapter<User> {

        UserAdapter(Context context, List<User> datas) {
            super(context, datas);

            addItemViewDelegate(new User0Delegate());
            addItemViewDelegate(new User1Delegate());

        }

        //ItemViewDelegate  每個(gè)條目的父類
        private class User0Delegate implements ItemViewDelegate<User> {

            @Override//返回條目的布局
            public int getItemViewLayoutId() {
                return R.layout.item_0;
            }

            @Override//判斷在什么條件下顯示該條目

            public boolean isForViewType(User user, int position) {
                return user.getType() == 0;
            }

            @Override
            public void convert(ViewHolder holder, User user, int position) {
                holder.setText(R.id.tv, user.getName());
            }
        }

        private class User1Delegate implements ItemViewDelegate<User> {

            @Override
            public int getItemViewLayoutId() {
                return R.layout.item_1;
            }

            @Override
            public boolean isForViewType(User item, int position) {
                return item.getType() == 1;
            }

            @Override
            public void convert(ViewHolder holder, User user, int position) {
                holder.setText(R.id.tv, user.getName());
            }
        }

    }

布局和上面是一樣的熊楼。這里多天目適配器需要繼承MultiItemTypeAdapter泛型也是數(shù)據(jù)類型霹娄。在里面我們必須要重寫構(gòu)造方法。這次我們沒有傳入item布局鲫骗,而是在MultiItemTypeAdapter中有創(chuàng)建2個(gè)實(shí)現(xiàn)ItemViewDelegate的適配器犬耻,因?yàn)閺男Ч麍D上也可以看出,是2中不用的效果所以兩種效果各自用各自的適配器然后在isForViewType判斷如果user.getType() == 0則用
User0Delegate適配器执泰。user.getType()是我們在創(chuàng)建實(shí)體時(shí)寫入的目的就是在此區(qū)分的枕磁。然后在MultiItemTypeAdapter構(gòu)造方法中調(diào)用addItemViewDelegate();將2中適配器加入到MultiItemTypeAdapter統(tǒng)一管理,外界只需要實(shí)例化MultiItemTypeAdapter就可以了术吝。這里我們用了2中不同的效果计济,當(dāng)然也可以更多。

  • 分組適配器

同樣先來看下效果:

asd.gif

這個(gè)效果有點(diǎn)像我們的手機(jī)通訊錄排苍。代碼如下:

·
  rv = (RecyclerView) findViewById(R.id.rv);
        rv.setLayoutManager(new LinearLayoutManager(this));

        for(int i = 0 ; i < 20 ; i ++){
            strList.add("我是section"+i);
        }

        SectionRVAdapter adapter = new SectionRVAdapter(this) ;
        adapter.addSection(new DataSection(this,"我是Section1",strList));
        adapter.addSection(new DataSection(this,"我是Section2",strList));
        adapter.addSection(new DataSection(this,"我是Section3",strList));

        rv.setLayoutManager(new LinearLayoutManager(this));
        rv.setAdapter(adapter);

    }

    //StatelessSection  添加section的父類
    public class DataSection extends StatelessSection{
        private String title ;
        private List<String> strList ;
        private Context context ;
        public DataSection(Context context ,String title ,List<String> strList) {
            super(R.layout.section_title,R.layout.section_content);
            this.title = title ;
            this.context = context ;
            this.strList = strList ;
        }
        @Override
        public int getContentItemsTotal() {
            return strList.size();
        }
        @Override
        public ViewHolder getItemViewHolder(View view, int viewType) {return new ViewHolder(context,view);
        }

        @Override
        public void onBindItemViewHolder(ViewHolder holder, int position) {
            String s = strList.get(position);
            holder.setText(R.id.tv,s);
        }

        @Override
        public ViewHolder getHeaderViewHolder(Context context, View view) {return new ViewHolder(context,view) ;}

        @Override
        public void onBindHeaderViewHolder(ViewHolder holder) {
            super.onBindHeaderViewHolder(holder);
            holder.setText(R.id.tv,title) ;
        }
    }

分組適配器需要繼承StatelessSection并實(shí)現(xiàn)構(gòu)造方法和3個(gè)抽象方法沦寂,同時(shí)我們又重寫了最后2個(gè)方法,實(shí)現(xiàn)添加頭部標(biāo)題分組的標(biāo)題(或者叫頭部)淘衙,頭部布局就是一個(gè)TextView传藏。這里我們new的ViewHolder是這個(gè)工具類自帶的。當(dāng)然也可以自己實(shí)現(xiàn)幔翰。里面的方法我用一張圖來解釋更加清晰漩氨。如下:

clipard.png

在使用時(shí)我們先創(chuàng)建SectionRVAdapter他是給RecyclerView添加標(biāo)題布局的一個(gè)適配器。然后調(diào)用他的addSection()方法加入我們創(chuàng)建好的適配器就可以使用了遗增。這里添加了三組叫惊,更多的話可以利用循環(huán)。這里注意StatelessSection有三個(gè)構(gòu)造方法分別對(duì)應(yīng)添加頭部做修,腳部霍狰,和上面都不添加。這里不要弄錯(cuò)饰及。添加上面效果就要在構(gòu)造方法加入相應(yīng)的item布局Id蔗坯。

  • 整體添加頭部腳部

效果圖:

asda.gif


·
  .....省略
        SectionRVAdapter adapter = new SectionRVAdapter(this) ;
        adapter.addSection(new DataSection(this,"我是Section1",strList));
        adapter.addSection(new DataSection(this,"我是Section2",strList));
        adapter.addSection(new DataSection(this,"我是Section3",strList));

        TopWrapper topWrapper = new TopWrapper(adapter);

        rv.setLayoutManager(new LinearLayoutManager(this));
        rv.setAdapter(topWrapper)
    //HeaderAndFooterWrapper  是頭的父類
    public class TopWrapper extends HeaderAndFooterWrapper{

        public TopWrapper(RecyclerView.Adapter adapter) {
            super(adapter);
            View view = View.inflate(Main5Activity.this,R.layout.top,null);
            addHeaderView(view);//添加頭部布局
            addFootView(view);//添加腳部布局
        }
    }
.....省略

我們可以在頭部添加輪播圖之類的。這里代碼沒有改變只是創(chuàng)建了頭部布局TopWrapper繼承HeaderAndFooterWrapper燎含。這里需要注意SectionRVAdapter是在多種類條目的情況下給每種條目添加頭部宾濒。而HeaderAndFooterWrapper是給整個(gè)RecyclerView添加頭部,當(dāng)只有單條目時(shí)添加頭部用哪種都可以屏箍,這里需要區(qū)分下绘梦。關(guān)系HeaderAndFooterWrapper<-SectionRVAdapter<-StatelessSection,這里的箭頭是包含關(guān)系橘忱。
注意: 在使用HeaderAndFooterWrapper時(shí)頭部腳部布局中最外層要用RelativeLayout否則會(huì)出現(xiàn)android:layout_width="match_parent"無效。


結(jié)語

這個(gè)適配器稱之為萬能適配器我覺得都不為過卸奉。不管你是多復(fù)雜的布局只要用到RecyclerView钝诚,全部都能實(shí)現(xiàn)。用法基本上都講到了榄棵,也全都覆蓋了凝颇。里面沒有講到的大家可以再繼續(xù)研究。源碼就在百籃應(yīng)用中的recyclerviewlibrary這個(gè)Module大家使用只需要依賴這個(gè)即可疹鳄。如果你是想通過這個(gè)項(xiàng)目這篇文章也可以幫到你拧略。有什么問題大家給我留言,對(duì)你有幫助的話留個(gè)言尚辑,價(jià)格關(guān)注辑鲤。我會(huì)更有動(dòng)力的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末杠茬,一起剝皮案震驚了整個(gè)濱河市月褥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瓢喉,老刑警劉巖宁赤,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異栓票,居然都是意外死亡决左,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門走贪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來佛猛,“玉大人,你說我怎么就攤上這事坠狡〖陶遥” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵逃沿,是天一觀的道長婴渡。 經(jīng)常有香客問我,道長凯亮,這世上最難降的妖魔是什么边臼? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮假消,結(jié)果婚禮上柠并,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好臼予,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布亿傅。 她就那樣靜靜地躺著,像睡著了一般瘟栖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谅阿,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天半哟,我揣著相機(jī)與錄音,去河邊找鬼签餐。 笑死寓涨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的氯檐。 我是一名探鬼主播戒良,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼冠摄!你這毒婦竟也來了糯崎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤河泳,失蹤者是張志新(化名)和其女友劉穎沃呢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拆挥,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡薄霜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纸兔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惰瓜。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖汉矿,靈堂內(nèi)的尸體忽然破棺而出崎坊,到底是詐尸還是另有隱情,我是刑警寧澤负甸,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布流强,位于F島的核電站,受9級(jí)特大地震影響呻待,放射性物質(zhì)發(fā)生泄漏打月。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一蚕捉、第九天 我趴在偏房一處隱蔽的房頂上張望奏篙。 院中可真熱鬧,春花似錦、人聲如沸秘通。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肺稀。三九已至第股,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間话原,已是汗流浹背夕吻。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留繁仁,地道東北人涉馅。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像黄虱,于是被迫代替她去往敵國和親稚矿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容