過(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ò)展:
-
twoway-view 封裝了RecyclerView常用方法,如click等等,以及支持了更多不同的布局呀袱,使得RecyclerView使用起來(lái)更簡(jiǎn)單贸毕!