一、開(kāi)發(fā)Android的程序員都知道LIstView,2014年Google Android L 版發(fā)布,新的控件RecyclerView取代之前ListView,為什么Google要取代它,通過(guò)自己實(shí)踐使用,發(fā)現(xiàn)它比ListView有以下幾大有點(diǎn):
1.提供了一種插拔式的體驗(yàn),高度的解耦,異常的靈活使用
2.顯示的樣式更豐富包括水平,豎直,Grid,瀑布顯示方式
3.可以通過(guò)ItemDecoration自定義Item間的間隔
4.可以通過(guò)ItemAnimator自定義Item增、刪動(dòng)畫(huà)(也可設(shè)置默認(rèn)動(dòng)畫(huà))
5.代碼內(nèi)聚不需要手動(dòng)創(chuàng)建ViewHolder
二 、使用RecyclerView先了解他們的用處
1.RecyclerView.LayoutManager--------負(fù)責(zé)item顯示方式
2.RecyclerView.Adapter---------------處理數(shù)據(jù)集合并負(fù)責(zé)綁定視圖
3.ViewHolder------------------------持有item所有的用于綁定數(shù)據(jù)的View
4.ItemDecoration---------------------負(fù)責(zé)繪制Item附近的分割線
5.ItemAnimator-----------------------為Item的一般操作添加動(dòng)畫(huà)效果
LayoutManager主要作用是,測(cè)量和擺放RecyclerView中itemView,以及當(dāng)itemView對(duì)用戶不可見(jiàn)時(shí)循環(huán)復(fù)用處理。 通過(guò)設(shè)置Layout Manager的屬性,可以實(shí)現(xiàn)水平滾動(dòng)、垂直滾動(dòng)、Gird,瀑布顯示
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));設(shè)置橫向布局
當(dāng)然還可以設(shè)置Gird布局GridLayoutManager,瀑布布局StaggeredGridLayoutManager
還有一些其他的API:
findFirstVisibleItemPosition()返回當(dāng)前第一個(gè)可見(jiàn)Item的position
findFirstCompletelyVisibleItemPosition()返回當(dāng)前第一個(gè)完全可見(jiàn)Item的position
findLastVisibleItemPosition()返回當(dāng)前最后一個(gè)可見(jiàn)Item的position
findLastCompletelyVisibleItemPosition()返回當(dāng)前最后一個(gè)完全可見(jiàn)Item的position
RecyclerView.Adapter扮演著兩個(gè)角色。一、根據(jù)不同ViewType創(chuàng)建與之相應(yīng)的的Item-Layout,二、訪問(wèn)數(shù)據(jù)集合并將數(shù)據(jù)綁定到正確的View上。這就需要我們重寫(xiě)以下函數(shù):
public VH onCreateViewHolder(ViewGroup parent, int viewType)創(chuàng)建Item視圖,并返回相應(yīng)的ViewHolder
public void onBindViewHolder(VH holder, int position)綁定數(shù)據(jù)到正確的Item視圖上。
public int getItemCount() 返回該Adapter所持有的Itme數(shù)量
public class MyAdapter extends RecyclerView.Adapter {
public String[] datas = null;
public MyAdapter(String[] datas) {
this.datas = datas;
}
//創(chuàng)建新View,被LayoutManager所調(diào)用
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item,viewGroup,false);
ViewHolder vh = new ViewHolder(view);
return vh;
}
//將數(shù)據(jù)與界面進(jìn)行綁定的操作
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
viewHolder.mTextView.setText(datas[position]);
}
//獲取數(shù)據(jù)的數(shù)量
@Override
public int getItemCount() {
return datas.length;
}
//自定義的ViewHolder,持有每個(gè)Item的的所有界面元素
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView mTextView;
public ViewHolder(View view){
super(view);
mTextView = (TextView) view.findViewById(R.id.text);
}
}
}
RecyclerView.ItemDecoration通過(guò)設(shè)置recyclerView.addItemDecoration(new DividerDecoration(this));來(lái)改變Item之間的偏移量或者對(duì)Item進(jìn)行裝飾。當(dāng)然,你也可以對(duì)RecyclerView設(shè)置多個(gè)ItemDecoration,列表展示的時(shí)候會(huì)遍歷所有的ItemDecoration并調(diào)用里面的繪制方法,對(duì)Item進(jìn)行裝飾。RecyclerView.ItemDecoration是一個(gè)抽象類,可以通過(guò)重寫(xiě)以下三個(gè)方法,來(lái)實(shí)現(xiàn)Item之間的偏移量或者裝飾效果:
public void onDraw(Canvas c, RecyclerView parent) 裝飾的繪制在Item條目繪制之前調(diào)用,所以這有可能被Item的內(nèi)容所遮擋
public void onDrawOver(Canvas c, RecyclerView parent) 裝飾的繪制在Item條目繪制之后調(diào)用,因此裝飾將浮于Item之上
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) 與padding或margin類似,LayoutManager在測(cè)量階段會(huì)調(diào)用該方法,計(jì)算出每一個(gè)Item的正確尺寸并設(shè)置偏移量。
RecyclerView.ItemAnimator,ItemAnimator能夠幫助Item實(shí)現(xiàn)獨(dú)立的動(dòng)畫(huà)。ItemAnimator作觸發(fā)于以下三種事件:
1.某條數(shù)據(jù)被插入到數(shù)據(jù)集合中
2.從數(shù)據(jù)集合中移除某條數(shù)據(jù)
3.更改數(shù)據(jù)集合中的某條數(shù)據(jù)
幸運(yùn)的是,在Android中默認(rèn)實(shí)現(xiàn)了一個(gè)DefaultItemAnimator,我們可以通過(guò)以下代碼為Item增加動(dòng)畫(huà)效果:
recyclerView.setItemAnimator(new DefaultItemAnimator());
在之前的版本中,當(dāng)時(shí)據(jù)集合發(fā)生改變時(shí),我們通過(guò)調(diào)用.notifyDataSetChanged(),來(lái)刷新列表,因?yàn)檫@樣做會(huì)觸發(fā)列表的重繪,所以并不會(huì)出現(xiàn)任何動(dòng)畫(huà)效果,因此需要調(diào)用一些以notifyItem*()作為前綴的特殊方法,比如:
public final void notifyItemInserted(int position) 向指定位置插入Item
public final void notifyItemRemoved(int position) 移除指定位置Item
public final void notifyItemChanged(int position) 更新指定位置Item
三、Recycler設(shè)置監(jiān)聽(tīng)Listeners
當(dāng)使用了一段時(shí)間的RecyclerView,發(fā)現(xiàn)為其每一項(xiàng)添加點(diǎn)擊事件并沒(méi)有ListView那么輕松,像ListView直接加個(gè)OnItemClickListener就行了。實(shí)際上我們不要把RecyclerView當(dāng)做ListView的一個(gè)升級(jí)版,希望大家把他看做一個(gè)容器,同時(shí)里面包含了很多不同的Item,它們可以以不同方式排列組合,非常靈活,點(diǎn)擊方式你可以按照你自己的意愿進(jìn)行實(shí)現(xiàn)。
本節(jié)主要講解如何為RecyclerView添加點(diǎn)擊事件, 并簡(jiǎn)單介紹如何進(jìn)行Item增加刪除。
添加點(diǎn)擊事件
上面講了如何使用RecyclerView的Adpater,其實(shí)我們會(huì)發(fā)現(xiàn),Adapter是添加點(diǎn)擊事件一個(gè)很好的地方,里面是構(gòu)造布局等View的主要場(chǎng)所,也是數(shù)據(jù)和布局進(jìn)行綁定的地方。首先我們?cè)贏dapter中創(chuàng)建一個(gè)實(shí)現(xiàn)點(diǎn)擊接口,其中view是點(diǎn)擊的Item,data是我們的數(shù)據(jù),因?yàn)槲覀兿胫牢尹c(diǎn)擊的區(qū)域部分的數(shù)據(jù)是什么,以便我下一步進(jìn)行操作:
public static interface OnRecyclerViewItemClickListener {
void onItemClick(View view , DataModel data);
}
定義完接口,添加接口和設(shè)置Adapter接口的方法:
private OnRecyclerViewItemClickListener mOnItemClickListener = null;
public void setOnItemClickListener(OnRecyclerViewItemClickListener listener) {
this.mOnItemClickListener = listener;
}
那么這個(gè)接口用在什么地方呢?如下代碼所示,我們?yōu)锳dapter實(shí)現(xiàn)OnClickListener方法:
public class MyAdapter extends RecyclerView.Adapter implements View.OnClickListener{
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, final int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
ViewHolder vh = new ViewHolder(view);
//將創(chuàng)建的View注冊(cè)點(diǎn)擊事件
view.setOnClickListener(this);
return vh;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, final int i) {
viewHolder.mTextView.setText(datas.get(i).title);
//將數(shù)據(jù)保存在itemView的Tag中,以便點(diǎn)擊時(shí)進(jìn)行獲取
viewHolder.itemView.setTag(datas.get(i));
}
...
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
//注意這里使用getTag方法獲取數(shù)據(jù)
mOnItemClickListener.onItemClick(v,(DataModel)v.getTag());
}
}
...
}
做完這些事情,我們就可以在Activity或其他地方為RecyclerView添加項(xiàng)目點(diǎn)擊事件了,如在MainActivity中:
mAdapter = new MyAdapter(getDummyDatas());
mRecyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new MyAdapter.OnRecyclerViewItemClickListener() {
@Override
public void onItemClick(View view, DataModel data) {
//DO your fucking bussiness here!
}
});
完成了以上代碼就可以為RecyclerView添加項(xiàng)目點(diǎn)擊事件了,下面我們來(lái)看看RecyclerView如何添加和刪除數(shù)據(jù)并在界面上顯示。
添加刪除數(shù)據(jù)
以前在ListView當(dāng)中,我們只要修改后數(shù)據(jù)用Adapter的notifyDatasetChange一下就可以更新界面。然而在RecyclerView中還有一些更高級(jí)的用法:
添加數(shù)據(jù):
public void addItem(DataModel content, int position) {
datas.add(position, content);
notifyItemInserted(position); //Attention!
}
刪除數(shù)據(jù):
public void removeItem(DataModel model) {
int position = datas.indexOf(model);
datas.remove(position);
notifyItemRemoved(position);//Attention!
}