快速掌握RecyclerView

過(guò)去的這一兩年宫屠, RecyclerView越來(lái)越引起了我們Android開發(fā)人員的注意列疗,RecyclerView的靈活性還有性能上有很大的提升。
想必大家或多或少的接觸過(guò)或者了解過(guò)RecyclerView浪蹂,為什么沒有用起來(lái)抵栈,原因大概如下告材?

  • 大家對(duì)于ListView的熟悉、古劲,ListView基本可以滿足應(yīng)用的大部分場(chǎng)景斥赋,為什么要換RecyclerView?
  • ListView穩(wěn)定产艾,有很多相關(guān)開源庫(kù)疤剑,特別的好用。
  • RecyclerView不能添加頭布局闷堡,而ListView可以隘膘。

RecyclerView有什么優(yōu)缺點(diǎn)?如何使用RecyclerView和解決這些問(wèn)題杠览?

RecyclerView 的使用和優(yōu)點(diǎn)

  • 布局效果

RecyclerView最大的優(yōu)勢(shì)就是靈活棘幸,RecyclerView 同時(shí)支持 線性布局網(wǎng)格布局倦零、瀑布流布局三種误续,而且還能夠控制橫向還是縱向滾動(dòng)。

RecyclerView.LayoutManager扫茅,這是一個(gè)抽象類蹋嵌,系統(tǒng)提供了3個(gè)實(shí)現(xiàn)類:

  • LinearLayoutManager 線性管理器,支持橫向葫隙、縱向栽烂。
  • GridLayoutManager 網(wǎng)格布局管理器
  • StaggeredGridLayoutManager 瀑布就式布局管理器

注意:在實(shí)例化RecyclerView之后,我們需要使用setLayoutManager()給它設(shè)置布局管理器

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); // 創(chuàng)建線性布局管理器
      linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); // 設(shè)置線性布局為橫向(默認(rèn)為縱向)
      mRecyclerView.setLayoutManager(linearLayoutManager); // 設(shè)置布局管理器
  • 自帶ViewHolder

    RecyclerView.Adapter恋脚,比BaseAdapter做了更好的封裝腺办,強(qiáng)制需要?jiǎng)?chuàng)建ViewHolder,這樣的好處就是避免了初學(xué)者寫性能不佳的代碼

    繼承重寫 RecyclerView.Adapter 和 RecyclerView.ViewHolder

// 第一步:繼承重寫 RecyclerView.Adapter 和 RecyclerView.ViewHolder
public class AuthorRecyclerAdapter extends RecyclerView.Adapter<AuthorRecyclerAdapter.AuthorViewHolder> {

    @Override
    public AuthorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(AuthorViewHolder holder, int position) {

    }

    @Override
    public int getItemCount() {
        if (list == null) {
            return 0;
        }
        return list.size();
    }

    class AuthorViewHolder extends RecyclerView.ViewHolder {

        public AuthorViewHolder(View itemView) {
            super(itemView);

        }
    }
}
  • 控制item的間隔分割線糟描,

可以使用addItemDecoration(ItemDecoration decor)怀喉,不過(guò)里邊的ItemDecoration是一個(gè)抽象類,需要自己去實(shí)現(xiàn)

  • 實(shí)現(xiàn)增刪動(dòng)畫

通過(guò)setItemAnimator(ItemAnimator animator)可以實(shí)現(xiàn)增刪動(dòng)畫
RecyclerView自帶添加船响、刪除動(dòng)畫躬拢,而ListView則需添加額外的代碼才能實(shí)現(xiàn)。

刪除調(diào)用RecyclerView的adapter的notifyItemRemoved
添加調(diào)用RecyclerView的adapter的notifyItemInserted

說(shuō)到adapter我們就來(lái)說(shuō)說(shuō)RecyclerView.Adapter和BaseAdapter相比见间,額外提供了一下這些方法:

// 數(shù)據(jù)發(fā)生了改變聊闯,那調(diào)用這個(gè)方法,傳入改變對(duì)象的位置米诉。
public final void notifyItemChanged(int position);
// 可以刷新從positionStart開始itemCount數(shù)量的item了
public final void notifyItemRangeChanged(int positionStart, int itemCount);
// 添加菱蔬,傳入對(duì)象的位置。
public final void notifyItemInserted(int position);
// 刪除,傳入對(duì)象的位置拴泌。
public final void notifyItemRemoved(int position);
// 對(duì)象從fromPosition移動(dòng)到toPosition
public final void notifyItemMoved(int fromPosition, int toPosition);
//批量添加
public final void notifyItemRangeInserted(int positionStart, int itemCount);
//批量刪除
public final void notifyItemRangeRemoved(int positionStart, int itemCount);

如何為RecyclerView添加Header和Footer

  • 在MyAdapter類中犹褒,提供setHeaderView()和setFooterView()兩個(gè)方法,我們就是通過(guò)這兩個(gè)方法從Activity將headerView和footerView傳遞過(guò)來(lái)的弛针,利用getItemViewType()返回Item的類型,根據(jù)不同的類型李皇,我們創(chuàng)建不同的Item的View削茁。
package com.study.wnw.recyclerviewheaderfooter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
/** * Created by wnw on 16-5-20. */
public class MyAdapter extendsRecyclerView.Adapter<RecyclerView.ViewHolder> {
   public static final int TYPE_HEADER = 0;  //說(shuō)明是帶有Header的
   public static final int TYPE_FOOTER = 1;  //說(shuō)明是帶有Footer的
   public static final int TYPE_NORMAL = 2;  //說(shuō)明是不帶有header和footer的

   //獲取從Activity中傳遞過(guò)來(lái)每個(gè)item的數(shù)據(jù)集合
   private List<String> mDatas;
   //HeaderView, FooterView
   private View mHeaderView;
   private View mFooterView;

   //構(gòu)造函數(shù)
   public MyAdapter(List<String> list){
       this.mDatas = list;
   }

   //HeaderView和FooterView的get和set函數(shù)
   public View getHeaderView() {
       return mHeaderView;
   }
   public void setHeaderView(View headerView) {
       mHeaderView = headerView;
       notifyItemInserted(0);
   }
   public View getFooterView() {
       return mFooterView;
   }
   public void setFooterView(View footerView) {
       mFooterView = footerView;
       notifyItemInserted(getItemCount()-1);
   }

   /** 重寫這個(gè)方法,很重要掉房,是加入Header和Footer的關(guān)鍵茧跋,我們通過(guò)判斷item的類型,從而綁定不同的view    * */
   @Override
   public int getItemViewType(int position) {
       if (mHeaderView == null && mFooterView == null){
           return TYPE_NORMAL;
       }
       if (position == 0){
           //第一個(gè)item應(yīng)該加載Header
           return TYPE_HEADER;
       }
       if (position == getItemCount()-1){
           //最后一個(gè),應(yīng)該加載Footer
           return TYPE_FOOTER;
       }
       return TYPE_NORMAL;
   }

    //創(chuàng)建View卓囚,如果是HeaderView或者是FooterView瘾杭,直接在Holder中返回
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
       if(mHeaderView != null && viewType == TYPE_HEADER) {
           return new ListHolder(mHeaderView);
       }
       if(mFooterView != null && viewType == TYPE_FOOTER){
           return new ListHolder(mFooterView);
       }
       View layout = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
       return new ListHolder(layout);
   }

   //綁定View,這里是根據(jù)返回的這個(gè)position的類型哪亿,從而進(jìn)行綁定的粥烁,   HeaderView和FooterView, 就不同綁定了
   @Override
   public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
       if(getItemViewType(position) == TYPE_NORMAL){
           if(holder instanceof ListHolder) {
               //這里加載數(shù)據(jù)的時(shí)候要注意,是從position-1開始蝇棉,因?yàn)閜osition==0已經(jīng)被header占用了
               ((ListHolder) holder).tv.setText(mDatas.get(position-1));
               return;
           }
           return;
       }else if(getItemViewType(position) == TYPE_HEADER){
           return;
       }else{
          return;
        }
     }

   //在這里面加載ListView中的每個(gè)item的布局
   class ListHolder extends RecyclerView.ViewHolder{
       TextView tv;
       public ListHolder(View itemView) {
           super(itemView);
           //如果是headerview或者是footerview,直接返回
           if (itemView == mHeaderView){
               return;
           }
           if (itemView == mFooterView){
               return;
           }
           tv = (TextView)itemView.findViewById(R.id.item);
        }
   }

   //返回View中Item的個(gè)數(shù)讨阻,這個(gè)時(shí)候,總的個(gè)數(shù)應(yīng)該是ListView中Item的個(gè)數(shù)加上HeaderView和FooterView
   @Override
   public int getItemCount() {
       if(mHeaderView == null && mFooterView == null){
           return mDatas.size();
       }else if(mHeaderView == null && mFooterView != null){
           return mDatas.size() + 1;
       }else if (mHeaderView != null && mFooterView == null){
           return mDatas.size() + 1;
       }else {
           return mDatas.size() + 2;
       }
   }
}
  • 在Activity添加布局
mMyAdapter.setHeaderView(header);
mMyAdapter.setFooterView(footer);

如何給RecyclerView添加點(diǎn)擊事件

RecyclerView強(qiáng)大篡殷,好用钝吮,但是使用率很高的ItemClickListener卻沒有添加。

點(diǎn)擊事件的實(shí)現(xiàn)板辽,有常見的三種方法:

  • 通過(guò) RecyclerView已有的方法 addOnItemTouchListener()實(shí)現(xiàn)
  • 在創(chuàng)建 ItemView時(shí)添加點(diǎn)擊監(jiān)聽
  • 當(dāng) ItemViewattach RecyclerView時(shí)實(shí)現(xiàn)

具體參考:給RecyclerView封裝個(gè)Adapter吧(更優(yōu)雅的添加點(diǎn)擊事件)

更多功能介紹將持續(xù)更新中奇瘦。。劲弦。耳标。。邑跪。

參考文獻(xiàn) 及相關(guān)框架:

基礎(chǔ)篇:

擴(kuò)展:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市夜赵,隨后出現(xiàn)的幾起案子明棍,更是在濱河造成了極大的恐慌,老刑警劉巖寇僧,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摊腋,死亡現(xiàn)場(chǎng)離奇詭異沸版,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)兴蒸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門视粮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人橙凳,你說(shuō)我怎么就攤上這事蕾殴。” “怎么了岛啸?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵钓觉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我坚踩,道長(zhǎng)荡灾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任瞬铸,我火速辦了婚禮批幌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嗓节。我一直安慰自己逼裆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布赦政。 她就那樣靜靜地躺著胜宇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪恢着。 梳的紋絲不亂的頭發(fā)上桐愉,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音掰派,去河邊找鬼从诲。 笑死,一個(gè)胖子當(dāng)著我的面吹牛靡羡,可吹牛的內(nèi)容都是我干的系洛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼略步,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼描扯!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起趟薄,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤绽诚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恩够,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡卒落,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蜂桶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片儡毕。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖扑媚,靈堂內(nèi)的尸體忽然破棺而出腰湾,到底是詐尸還是另有隱情,我是刑警寧澤钦购,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站褂萧,受9級(jí)特大地震影響押桃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜导犹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一唱凯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谎痢,春花似錦磕昼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至滨嘱,卻和暖如春峰鄙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背太雨。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工吟榴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人囊扳。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓吩翻,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親锥咸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子狭瞎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

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