以下内容為原創,歡迎轉載,轉載請注明
RecyclerView是一個比ListView更靈活的一個控件,以後可以直接抛棄ListView了。具體好在哪些地方,往下看就知道了。
首先我們來使用RecyclerView來實作ListView的效果,一個滾動清單,先看下效果圖(除了有動畫之外,沒什麼特别--):

每個item的布局如下:
item的布局很簡單,隻有兩個TextView,一個用來顯示名字,一個用來顯示年齡。
Person的實體類就不貼代碼了,兩個屬性:名字和年齡。
然後需要使用到RecyclerView,是以需要把support v7添加到class path,并在布局中添加該控件:
然後在onCreate中:
如上述代碼:
Line1: 使RecyclerView保持固定的大小,這樣會提高RecyclerView的性能。
Line3: LinearLayoutManager,如果你需要顯示的是橫向滾動的清單或者豎直滾動的清單,則使用這個LayoutManager。顯然,我們要實作的是ListView的效果,是以需要使用它。生成這個LinearLayoutManager之後可以設定他滾動的方向,預設豎直滾動,是以這裡沒有顯式地設定。
Line6: 初始化資料源。
Line7~9: 跟ListView一樣,需要設定RecyclerView的Adapter,但是這裡的Adapter跟ListView使用的Adapter不一樣,這裡的Adapter需要繼承RecyclerView.Adapter,需要實作3個方法:
- onCreateViewHolder()
- onBindViewHolder()
- getItemCount()
直接看代碼:
如上代碼所示:
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i)
這個方法主要生成為每個Item inflater出一個View,但是該方法傳回的是一個ViewHolder。方法是把View直接封裝在ViewHolder中,然後我們面向的是ViewHolder這個執行個體,當然這個ViewHolder需要我們自己去編寫。直接省去了當初的convertView.setTag(holder)和convertView.getTag()這些繁瑣的步驟。
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i)
這個方法主要用于适配渲染資料到View中。方法提供給你了一個viewHolder,而不是原來的convertView。
對比下以前的寫法就一目了然了:
對比後可以發現:
舊的寫法中Line5~Line12+Line28部分的代碼其實起到的作用相當于新的寫法的onCreateViewHolder();
舊的寫法中Line14~Line26部分的代碼其實起到的作用相當于新的寫法的onBindViewHolder();
既然是這樣,那我們就把原來相應的代碼搬到對應的onCreateViewHolder()和onBindViewHolder()這兩個方法中就可以了。
因為RecyclerView幫我們封裝了Holder,是以我們自己寫的ViewHolder就需要繼承RecyclerView.ViewHolder,隻有這樣,RecyclerView才能幫你去管理這個ViewHolder類。
既然getView方法的渲染資料部分的代碼相當于onBindViewHolder(),是以如果調用adapter.notifyDataSetChanged()方法,應該也會重新調用onBindViewHolder()方法才對吧?實驗後,果然如此!
除了adapter.notifyDataSetChanged()這個方法之外,新的Adapter還提供了其他的方法,如下:
基本上看到方法的名字就知道這個方法是幹嘛的了,
第一個方法沒什麼好講的,跟以前一樣。
notifyItemChanged(int position),position資料發生了改變,那調用這個方法,就會回調對應position的onBindViewHolder()方法了,當然,因為ViewHolder是複用的,是以如果position在目前螢幕以外,也就不會回調了,因為沒有意義,下次position滾動會目前螢幕以内的時候同樣會調用onBindViewHolder()方法重新整理資料了。其他的方法也是同樣的道理。
public final void notifyItemRangeChanged(int positionStart, int itemCount),顧名思義,可以重新整理從positionStart開始itemCount數量的item了(這裡的重新整理指回調onBindViewHolder()方法)。
public final void notifyItemInserted(int position),這個方法是在第position位置被插入了一條資料的時候可以使用這個方法重新整理,注意這個方法調用後會有插入的動畫,這個動畫可以使用預設的,也可以自己定義。
public final void notifyItemMoved(int fromPosition, int toPosition),這個方法是從fromPosition移動到toPosition為止的時候可以使用這個方法重新整理
public final void notifyItemRangeInserted(int positionStart, int itemCount),顯然是批量添加。
public final void notifyItemRemoved(int position),第position個被删除的時候重新整理,同樣會有動畫。
public final void notifyItemRangeRemoved(int positionStart, int itemCount),批量删除。
這些方法分析完之後,我們來實作一個點選一個按鈕,新增一條資料,長按一個item,删除一條資料的場景。
以下是新增一條資料的代碼:
如上代碼:
Line2:表示在position為2的位置,插入一條資料,這個時候動畫開始執行。
Line3: 表示在資料源中position為2的位置新增一條資料(其實這個才是真正的新增資料啦)。
Line4: 為什麼要重新整理position為2以後的資料呢?因為,在position為2的位置插入了一條資料後,新資料的position變成了2,那原來的position為2的應該變成了3,3的應該變成了4,是以2以後的所有資料的position都發生了改變,是以需要把position2以後的資料都要重新整理。理論上是這樣,但是實際上重新整理的數量隻有在螢幕上顯示的position為2以後的資料而已。如果這裡使用notifyDataSetChanged()來重新整理螢幕上顯示的所有item可以嗎?結果不會出錯,但是會有一個問題,前面調用了notifyItemInserted()方法後會在執行動畫,如果你調用notifyDataSetChanged()重新整理螢幕上顯示的所有item的話,必然也會重新整理目前正在執行動畫的那個item,這樣導緻的結果是,前面的動畫還沒執行完,它馬上又被重新整理了,動畫就看不見了。是以隻要重新整理2以後的item就可以了。
看了RecyclerView的api,發現沒有setOnItemClickListener--,是以還是自己把onItemClick從Adapter中回調出來吧。這個很簡單,就像上面PersonAdaper中寫的OnRecyclerViewListener那樣。
長按删除的代碼如下:
代碼跟之前插入的代碼基本一緻。先通知執行動畫,然後删除資料源中的資料,然後通知position之後的資料重新整理就可以了。
這樣ListView的效果就實作了。
示例代碼:
<a href="https://github.com/wangjiegulu/RecyclerViewSample" target="_blank">https://github.com/wangjiegulu/RecyclerViewSample</a>
<a href="http://www.cnblogs.com/tiantianbyconan/p/4242541.html" target="_blank">http://www.cnblogs.com/tiantianbyconan/p/4242541.html</a>
<a href="http://www.cnblogs.com/tiantianbyconan/p/4268097.html" target="_blank">http://www.cnblogs.com/tiantianbyconan/p/4268097.html</a>