概述
RecyclerView(一)使用完全指南
RecyclerView(二)之萬能分割線
RecyclerView之瀑布流(三)
官方介紹,RecyclerView用于在有限的窗口展現(xiàn)大量的數(shù)據(jù)查吊,其實(shí)早已經(jīng)有了類似的控件誊酌,如ListView纠亚、GridView龟劲,那么相比它們,RecyclerView有什么樣優(yōu)勢(shì)呢粪般?
RecyclerView標(biāo)準(zhǔn)化了ViewHolder有决,而且異常的靈活闸拿,可以輕松實(shí)現(xiàn)ListView實(shí)現(xiàn)不了的樣式和功能,通過布局管理器LayoutManager可控制Item的布局方式书幕,通過設(shè)置Item操作動(dòng)畫自定義Item添加和刪除的動(dòng)畫新荤,通過設(shè)置Item之間的間隔樣式,自定義間隔台汇。
- 設(shè)置布局管理器以控制Item的布局方式苛骨,橫向、豎向以及瀑布流方式励七。
- 可設(shè)置Item操作的動(dòng)畫(刪除或者添加等)
- 可設(shè)置Item的間隔樣式(可繪制)
- 但是關(guān)于Item的點(diǎn)擊和長(zhǎng)按事件智袭,需要用戶自己去實(shí)現(xiàn)。
在使用RecyclerView時(shí)候掠抬,必須指定一個(gè)適配器Adapter和一個(gè)布局管理器LayoutManager吼野。適配器繼承RecyclerView.Adapter類,具體實(shí)現(xiàn)類似ListView的適配器两波,取決于數(shù)據(jù)信息以及展示的UI瞳步。布局管理器用于確定RecyclerView中Item的展示方式以及決定何時(shí)復(fù)用已經(jīng)不可見的Item闷哆,避免重復(fù)創(chuàng)建以及執(zhí)行高成本的findViewById()方法。
來看一下用法单起。
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// 設(shè)置布局管理器
mRecyclerView.setLayoutManager(mLayoutManager);
// 設(shè)置adapter
mRecyclerView.setAdapter(mAdapter);
// 設(shè)置Item添加和移除的動(dòng)畫
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
// 設(shè)置Item之間間隔樣式(分割線)
mRecyclerView.addItemDecoration(new DividerItemDecoration(
getActivity(), DividerItemDecoration.HORIZONTAL_LIST));
可以看見RecyclerView相比ListView會(huì)多出許多操作抱怔,這也是RecyclerView靈活的地方,它將許多動(dòng)能暴露出來嘀倒,用戶可以選擇性的自定義屬性以滿足需求屈留。
RecyclerView提供了三種布局管理器:
- LinerLayoutManager 以垂直或者水平列表方式展示Item
- GridLayoutManager 以網(wǎng)格方式展示Item
- StaggeredGridLayoutManager 以瀑布流方式展示Item
基本使用
Activity代碼
public class HomeActivity extends ActionBarActivity
{
private RecyclerView mRecyclerView;
private List<String> mDatas;
private HomeAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_recyclerview);
initData();
mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mAdapter = new HomeAdapter());
}
protected void initData()
{
mDatas = new ArrayList<String>();
for (int i = 'A'; i < 'z'; i++)
{
mDatas.add("" + (char) i);
}
}
class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
{
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
HomeActivity.this).inflate(R.layout.item_home, parent,
false));
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position)
{
holder.tv.setText(mDatas.get(position));
}
@Override
public int getItemCount()
{
return mDatas.size();
}
class MyViewHolder extends ViewHolder
{
TextView tv;
public MyViewHolder(View view)
{
super(view);
tv = (TextView) view.findViewById(R.id.id_num);
}
}
}
}
Activity布局文件activity_rv.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Item的布局文件item_home.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="@dimen/md_common_view_height">
<TextView
android:id="@+id/item_tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
tools:text="item"/>
</LinearLayout>
運(yùn)行結(jié)果如下:
可以看見展示效果和ListView基本上無差別,但是Item之間并沒有分割線测蘑,在xml去找divider屬性的時(shí)候灌危,發(fā)現(xiàn)RecyclerView沒有divider屬性,當(dāng)然也可以在Item布局中加上分割線碳胳,但是這樣做并不是很優(yōu)雅勇蝙。前文說過,RecyclerView可是支持自定義間隔樣式的挨约。通過mRecyclerView.addItemDecoration()
來設(shè)置我們定義好的間隔樣式味混。
默認(rèn)分割線
水平分割線
mRecyclerView.addItemDecoration(new DividerItemDecoration(
getActivity(), LinerLayoutManager.HORIZONTAL));
垂直分割線
mRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL, false));
mRecyclerView.addItemDecoration(new DividerItemDecoration(
getActivity(), LinerLayoutManager.HORIZONTAL));
這里的HORIZONTAL
是設(shè)置垂直分割線 而DividerItemDecoration.VERTICAL
是設(shè)置水平分割線
注:如果布局管理器中的
LinearLayoutManager.HORIZONTAL
和分割線樣式LinearLayoutManager.VERTICAL
則不會(huì)顯示
動(dòng)畫
前面說過,RecyclerView可以設(shè)置列表中Item刪除和添加的動(dòng)畫诫惭,在v7包中給我們提供了一種默認(rèn)的Item刪除和添加的動(dòng)畫翁锡,如果沒有特殊的需求,默認(rèn)使用這個(gè)動(dòng)畫即可夕土。
// 設(shè)置Item添加和移除的動(dòng)畫
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
下面就添加一下刪除和添加Item的動(dòng)作盗誊。在Adapter里面添加方法。
public void addNewItem() {
if(mData == null) {
mData = new ArrayList<>();
}
mData.add(0, "new Item");
notifyItemInserted(0);
}
public void deleteItem() {
if(mData == null || mData.isEmpty()) {
return;
}
mData.remove(0);
notifyItemRemoved(0);
}
添加事件的處理隘弊。
public void onClick(View v) {
int id = v.getId();
if(id == R.id.rv_add_item_btn) {
mAdapter.addNewItem();
// 由于Adapter內(nèi)部是直接在首個(gè)Item位置做增加操作,增加完畢后列表移動(dòng)到首個(gè)Item位置
mLayoutManager.scrollToPosition(0);
} else if(id == R.id.rv_del_item_btn){
mAdapter.deleteItem();
// 由于Adapter內(nèi)部是直接在首個(gè)Item位置做刪除操作荒适,刪除完畢后列表移動(dòng)到首個(gè)Item位置
mLayoutManager.scrollToPosition(0);
}
}
準(zhǔn)備工作完畢后梨熙,來看一下運(yùn)行的效果。
點(diǎn)擊事件
RecyclerView并沒有像ListView一樣暴露出Item點(diǎn)擊事件或者長(zhǎng)按事件處理的api刀诬,也就是說使用RecyclerView時(shí)候咽扇,需要我們自己來實(shí)現(xiàn)Item的點(diǎn)擊和長(zhǎng)按等事件的處理。實(shí)現(xiàn)方法有很多陕壹,可以監(jiān)聽RecyclerView的Touch事件然后判斷手勢(shì)做相應(yīng)的處理质欲,也可以通過在綁定ViewHolder的時(shí)候設(shè)置監(jiān)聽,然后通過Apater回調(diào)出去糠馆,我們選擇第二種方法嘶伟,更加直觀和簡(jiǎn)單。
先看一下效果
原理
為RecyclerView的每個(gè)子item設(shè)置setOnClickListener又碌,然后在onClick中再調(diào)用一次對(duì)外封裝的接口九昧,將這個(gè)事件傳遞給外面的調(diào)用者绊袋。而“為RecyclerView的每個(gè)子item設(shè)置setOnClickListener”在Adapter中設(shè)置。其實(shí)直接在onClick中也能完全處理item的點(diǎn)擊事件铸鹰,但是這樣會(huì)破壞代碼的邏輯癌别。
步驟
1、在MyAdapter中定義接口
public interface OnItemClickListener{
void onItemClick(int position);
}
2蹋笼、聲明這個(gè)接口變量
private OnItemClickListener mItemClickListener;
3展姐、在onCreateViewHolder()中為每個(gè)item添加點(diǎn)擊事件
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(mContext, R.layout.item_linear, null);
RecyclerView.ViewHolder holder = new LinearViewholder(view);
//這兩句也可以這樣寫,效果都是一樣的
//View view =LayoutInflater.from(parent.getContext()).inflate(R.layout.item_home, parent, false);
//RecyclerView.ViewHolder holder =new ViewHolder
view.setOnClickListener(this);
return holder;
}
@Override
public void onClick(View v) {
if (mItemClickListener!=null){
mItemClickListener.onItemClick((Integer) v.getTag());
}
}
4、注意上面調(diào)用接口的onItemClick()中的v.getTag()方法剖毯,這需要在onBindViewHolder()方法中設(shè)置和item相關(guān)的數(shù)據(jù)
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
LinearViewholder viewholder = (LinearViewholder) holder;
viewholder.mTextView.setText(mList.get(position));
viewholder.itemView.setTag(position);
}
5圾笨、提供set方法
public void setItemClickListener(OnItemClickListener itemClickListener) {
mItemClickListener = itemClickListener;
}
6、在MainActivity中
MyRecyclerViewAdapter adapter = new MyRecyalerViewAdapter();
adapter.setItemClickListener(this);
@Override
public void onItemClick(int position) {
Toast.makeText(this, ""+position, Toast.LENGTH_SHORT).show();
}
上面這是一種算是比較負(fù)責(zé)的一種了吧速兔,下面介紹一種簡(jiǎn)單的墅拭,當(dāng)然上面的也要自己弄明白的
class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
{
//...
public interface OnItemClickLitener
{
void onItemClick(View view, int position);
void onItemLongClick(View view , int position);
}
private OnItemClickLitener mOnItemClickLitener;
public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
{
this.mOnItemClickLitener = mOnItemClickLitener;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position)
{
holder.tv.setText(mDatas.get(position));
// 如果設(shè)置了回調(diào),則設(shè)置點(diǎn)擊事件
if (mOnItemClickLitener != null)
{
holder.itemView.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemClick(holder.itemView, pos);
}
});
holder.itemView.setOnLongClickListener(new OnLongClickListener()
{
@Override
public boolean onLongClick(View v)
{
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
return false;
}
});
}
}
//...
}
根據(jù)王三的貓阿德加以改編