一、開發(fā)Android的程序員都知道LIstView,2014年Google Android L 版發(fā)布帘饶,新的控件RecyclerView取代之前ListView,為什么Google要取代它瓣铣,通過自己實踐使用干签,發(fā)現(xiàn)它比ListView有以下幾大有點:
1.提供了一種插拔式的體驗,高度的解耦砚尽,異常的靈活使用
2.顯示的樣式更豐富包括水平施无,豎直,Grid必孤,瀑布顯示方式
3.可以通過ItemDecoration自定義Item間的間隔
4.可以通過ItemAnimator自定義Item增猾骡、刪動畫(也可設(shè)置默認動畫)
5.代碼內(nèi)聚不需要手動創(chuàng)建ViewHolder
二 、使用RecyclerView先了解他們的用處
1.RecyclerView.LayoutManager--------負責(zé)item顯示方式
2.RecyclerView.Adapter---------------處理數(shù)據(jù)集合并負責(zé)綁定視圖
3.ViewHolder------------------------持有item所有的用于綁定數(shù)據(jù)的View
4.ItemDecoration---------------------負責(zé)繪制Item附近的分割線
5.ItemAnimator-----------------------為Item的一般操作添加動畫效果
LayoutManager主要作用是敷搪,測量和擺放RecyclerView中itemView兴想,以及當(dāng)itemView對用戶不可見時循環(huán)復(fù)用處理。 通過設(shè)置Layout Manager的屬性赡勘,可以實現(xiàn)水平滾動嫂便、垂直滾動、Gird,瀑布顯示
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));設(shè)置橫向布局
當(dāng)然還可以設(shè)置Gird布局GridLayoutManager闸与,瀑布布局StaggeredGridLayoutManager
還有一些其他的API:
findFirstVisibleItemPosition()返回當(dāng)前第一個可見Item的position
findFirstCompletelyVisibleItemPosition()返回當(dāng)前第一個完全可見Item的position
findLastVisibleItemPosition()返回當(dāng)前最后一個可見Item的position
findLastCompletelyVisibleItemPosition()返回當(dāng)前最后一個完全可見Item的position
RecyclerView.Adapter扮演著兩個角色毙替。一、根據(jù)不同ViewType創(chuàng)建與之相應(yīng)的的Item-Layout践樱,二厂画、訪問數(shù)據(jù)集合并將數(shù)據(jù)綁定到正確的View上。這就需要我們重寫以下函數(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ù)與界面進行綁定的操作
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
viewHolder.mTextView.setText(datas[position]);
}
//獲取數(shù)據(jù)的數(shù)量
@Override
public int getItemCount() {
return datas.length;
}
//自定義的ViewHolder,持有每個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通過設(shè)置recyclerView.addItemDecoration(new DividerDecoration(this));來改變Item之間的偏移量或者對Item進行裝飾忽洛。當(dāng)然抛人,你也可以對RecyclerView設(shè)置多個ItemDecoration,列表展示的時候會遍歷所有的ItemDecoration并調(diào)用里面的繪制方法脐瑰,對Item進行裝飾妖枚。RecyclerView.ItemDecoration是一個抽象類,可以通過重寫以下三個方法苍在,來實現(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在測量階段會調(diào)用該方法谚咬,計算出每一個Item的正確尺寸并設(shè)置偏移量膝晾。
RecyclerView.ItemAnimator冒黑,ItemAnimator能夠幫助Item實現(xiàn)獨立的動畫析校。ItemAnimator作觸發(fā)于以下三種事件:
1.某條數(shù)據(jù)被插入到數(shù)據(jù)集合中
2.從數(shù)據(jù)集合中移除某條數(shù)據(jù)
3.更改數(shù)據(jù)集合中的某條數(shù)據(jù)
幸運的是鳞尔,在Android中默認實現(xiàn)了一個DefaultItemAnimator滥比,我們可以通過以下代碼為Item增加動畫效果:
recyclerView.setItemAnimator(new DefaultItemAnimator());
在之前的版本中牙咏,當(dāng)時據(jù)集合發(fā)生改變時臼隔,我們通過調(diào)用.notifyDataSetChanged(),來刷新列表妄壶,因為這樣做會觸發(fā)列表的重繪摔握,所以并不會出現(xiàn)任何動畫效果,因此需要調(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)聽Listeners
當(dāng)使用了一段時間的RecyclerView,發(fā)現(xiàn)為其每一項添加點擊事件并沒有ListView那么輕松伊磺,像ListView直接加個OnItemClickListener就行了盛正。實際上我們不要把RecyclerView當(dāng)做ListView的一個升級版,希望大家把他看做一個容器屑埋,同時里面包含了很多不同的Item豪筝,它們可以以不同方式排列組合,非常靈活雀彼,點擊方式你可以按照你自己的意愿進行實現(xiàn)壤蚜。
本節(jié)主要講解如何為RecyclerView添加點擊事件, 并簡單介紹如何進行Item增加刪除。
添加點擊事件
上面講了如何使用RecyclerView的Adpater徊哑,其實我們會發(fā)現(xiàn)袜刷,Adapter是添加點擊事件一個很好的地方,里面是構(gòu)造布局等View的主要場所莺丑,也是數(shù)據(jù)和布局進行綁定的地方著蟹。首先我們在Adapter中創(chuàng)建一個實現(xiàn)點擊接口墩蔓,其中view是點擊的Item,data是我們的數(shù)據(jù)萧豆,因為我們想知道我點擊的區(qū)域部分的數(shù)據(jù)是什么奸披,以便我下一步進行操作:
public static interface OnRecyclerViewItemClickListener {
void onItemClick(View view , DataModel data);
}
定義完接口,添加接口和設(shè)置Adapter接口的方法:
private OnRecyclerViewItemClickListener mOnItemClickListener = null;
public void setOnItemClickListener(OnRecyclerViewItemClickListener listener) {
this.mOnItemClickListener = listener;
}
那么這個接口用在什么地方呢涮雷?如下代碼所示阵面,我們?yōu)锳dapter實現(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注冊點擊事件
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中,以便點擊時進行獲取
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添加項目點擊事件了样刷,如在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添加項目點擊事件了,下面我們來看看RecyclerView如何添加和刪除數(shù)據(jù)并在界面上顯示览爵。
添加刪除數(shù)據(jù)
以前在ListView當(dāng)中置鼻,我們只要修改后數(shù)據(jù)用Adapter的notifyDatasetChange一下就可以更新界面。然而在RecyclerView中還有一些更高級的用法:
添加數(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!
}