- 參考:
這是一篇Android RecyclerView使用介紹哦(好!) - 本文的源代碼:
RecyclerViews
一. RecyclerView的基礎(chǔ)用法
- 添加依賴
compile 'com.android.support:recyclerview-v7:25.2.0'
- xml使用布局
<!--下拉刷新控件-->
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_linear_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view_linear"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
- 新建recycler_item的布局(recyclerview中的item的布局,此處的布局是CardView嵌套了ImageView)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardElevation="@dimen/cardview_default_elevation"
app:cardCornerRadius="@dimen/cardview_default_radius"
android:layout_margin="8dp">
<ImageView
android:id="@+id/iv_meizi"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
</android.support.v7.widget.CardView>
- 新建Adapter
public class LinearRecyclerAdapter extends RecyclerView.Adapter<LinearRecyclerAdapter.ViewHolder> {
private Context mContext;
private List<Meizi> mMeiziList;
/*構(gòu)造函數(shù),進(jìn)行初始化(一般傳入context和數(shù)據(jù)列表)*/
public LinearRecyclerAdapter(Context context,List<Meizi> meiziList) {
mContext = context;
mMeiziList = meiziList;
}
/*創(chuàng)建ViewHolder*/
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_item_linear_recycler,parent,false);
return new ViewHolder(view);
}
/*數(shù)據(jù)綁定到ViewHolder*/
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Meizi meizi = mMeiziList.get(position);
Picasso.with(mContext).load(meizi.getImageUrl()).into(holder.mImageView);
}
/*item的數(shù)量,一般就是數(shù)據(jù)List的大小*/
@Override
public int getItemCount() {
return mMeiziList.size();
}
/*內(nèi)部類ViewHolder*/
class ViewHolder extends RecyclerView.ViewHolder {
private ImageView mImageView;
ViewHolder(View itemView) {
super(itemView);
mImageView = (ImageView) itemView.findViewById(R.id.iv_meizi);
}
}
/*添加item的函數(shù)*/
public void addItem(Meizi meizi, int position) {
mMeiziList.add(position, meizi);
notifyItemInserted(position);
}
/*滑動(dòng)刪除會(huì)調(diào)用的函數(shù)*/
public void removeItem(final int position) {
final Meizi removed=mMeiziList.get(position);
mMeiziList.remove(position);
notifyItemRemoved(position);
Toast.makeText(mContext,"你刪除了第"+position+"個(gè)item",Toast.LENGTH_SHORT).show();
}
}
- 實(shí)例化RecyclerView,設(shè)置布局管理器和Adapter
mRecyclerView = (RecyclerView) mRootView.findViewById(R.id.recycler_view_linear);//初始化recyclerview
mLayoutManager = new LinearLayoutManager(getContext());//初始化布局管理器
mRecyclerView.setLayoutManager(mLayoutManager);//設(shè)置布局管理器
- 獲取數(shù)據(jù),封裝到List中罗捎,實(shí)例化Adapter,給RecyclerView設(shè)置Adapter
二. 下拉刷新的實(shí)現(xiàn)
- 實(shí)例化SwipeRefreshLayout
/*初始化下拉刷新控件*/
mSwipeRefreshLayout = (SwipeRefreshLayout) mRootView.findViewById(R.id.swipe_refresh_linear_recycler);
- 下拉刷新監(jiān)聽
/*swipeRefreshLayout刷新監(jiān)聽*/
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
//下拉刷新之后要進(jìn)行的操作拉盾,一般是重新加載數(shù)據(jù)
new GetMeiziTask().execute("http://gank.io/api/data/福利/10/1 ");
}
});
- 刷新之后記得調(diào)用
mSwipeRefreshLayout.setRefreshing(false);
取消顯示刷新的按鈕桨菜,每次在刷新之前可以調(diào)用mSwipeRefreshLayout.setRefreshing(true);
顯示刷新按鈕(一般在AsyncTask的onPreExecute中)
三. 滑動(dòng)刪除和長按交換位置的實(shí)現(xiàn)
- 原理
- 滑動(dòng)刪除就是監(jiān)聽滑動(dòng)事件,然后在回調(diào)方法中捉偏,將數(shù)據(jù)list中的對(duì)應(yīng)元素刪除
- 長按交換位置就是長按事件倒得,然后在回調(diào)方法中,將數(shù)據(jù)list中的對(duì)應(yīng)元素進(jìn)行移動(dòng)
- 使用方法
- 實(shí)例化ItemTouchHelper類夭禽,在回調(diào)方法中實(shí)現(xiàn)滑動(dòng)刪除
/*item觸摸助手類霞掺,用于實(shí)現(xiàn)滑動(dòng)刪除等操作*/
mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
//用于設(shè)置拖拽和滑動(dòng)的方向
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags=0,swipeFlags=0;
if(recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager ||recyclerView.getLayoutManager() instanceof GridLayoutManager){
//網(wǎng)格式布局有4個(gè)方向
dragFlags=ItemTouchHelper.UP|ItemTouchHelper.DOWN|ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT;
}else if(recyclerView.getLayoutManager() instanceof LinearLayoutManager){
//線性式布局有2個(gè)方向
dragFlags=ItemTouchHelper.UP|ItemTouchHelper.DOWN;
swipeFlags = ItemTouchHelper.START|ItemTouchHelper.END; //設(shè)置側(cè)滑方向?yàn)閺膬蓚€(gè)方向都可以
}
return makeMovementFlags(dragFlags,swipeFlags);//swipeFlags 為0的話item不滑動(dòng)
}
//長摁item拖拽時(shí)會(huì)回調(diào)這個(gè)方法
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
/*int from=viewHolder.getAdapterPosition();
int to=target.getAdapterPosition();
Meizi moveItem=mMeiziList.get(from);
mMeiziList.remove(from);
mMeiziList.add(to,moveItem);//交換數(shù)據(jù)鏈表中數(shù)據(jù)的位置
mLinearRecyclerAdapter.notifyItemMoved(from,to);//更新適配器中item的位置*/
int from=viewHolder.getAdapterPosition();
int to=target.getAdapterPosition();
Collections.swap(mMeiziList,from,to);
mLinearRecyclerAdapter.notifyItemMoved(from,to);
return true;
}
/*滑動(dòng)刪除*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mLinearRecyclerAdapter.removeItem(viewHolder.getAdapterPosition());
}
});
- 將ItemTouchHelper與RecyclerView綁定
mItemTouchHelper.attachToRecyclerView(mRecyclerView);//觸摸事件關(guān)聯(lián)到RecyclerView
四. 簡單的RecyclerItem動(dòng)畫的實(shí)現(xiàn)
/*設(shè)置item加載或移除時(shí)的動(dòng)畫*/
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
五. item的點(diǎn)擊事件實(shí)現(xiàn)
- 在Adapter里面實(shí)現(xiàn)事件監(jiān)聽
- 在ViewHolder里直接給控件添加監(jiān)聽事件
ViewHolder(View itemView) {
super(itemView);
mImageView = (ImageView) itemView.findViewById(R.id.iv_meizi);
mImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext,"You clicked item "+getAdapterPosition(),Toast.LENGTH_SHORT).show();
}
});
}
- 在onBindViewHolder方法里給控件添加監(jiān)聽事件
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
Meizi meizi = mMeiziList.get(position);
Picasso.with(mContext).load(meizi.getImageUrl()).into(holder.mImageView);
/*holder.mImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext,"You clicked item "+holder.getAdapterPosition(),Toast.LENGTH_SHORT).show();
}
});*/
}
- 在調(diào)用的地方實(shí)現(xiàn)回調(diào)的監(jiān)聽和處理
- Adapter實(shí)現(xiàn)回掉接口,在調(diào)用處進(jìn)行調(diào)用
六. 上拉加載
- 上拉加載就是先設(shè)置onScrollListener讹躯,在listener方法里面進(jìn)行判斷然后加載數(shù)據(jù)菩彬,加載數(shù)據(jù)的原理是獲取新的數(shù)據(jù)然后添加到List集合中,然后再調(diào)用Adapter的notifyDataSetChanged通知更新數(shù)據(jù)潮梯。
七. 四大角色
- RecyclerView
RecyclerView就是一個(gè)控件骗灶,和普通控件一樣,只不過他的作用是用來展示列表秉馏,回收和定位屏幕上的view
- Adapter
適配器耙旦,用來創(chuàng)建RecyclerView的界面(ViewHolder),加載數(shù)據(jù)到界面上萝究,當(dāng)RecyclerView需要顯示view時(shí)免都,就會(huì)去找它的adapter锉罐。具體過程如下:
- 調(diào)用adapter的getIemCount()方法,詢問列表對(duì)象的總個(gè)數(shù)
- 調(diào)用adapter的createViewHolder()方法绕娘,創(chuàng)建ViewHolder和要顯示的視圖
- 傳入ViewHolder和要加載的視圖位置脓规,調(diào)用adapter的onBindViewHolder()方法,為視圖綁定數(shù)據(jù)
每當(dāng)需要加載一個(gè)item的時(shí)候就會(huì)調(diào)用以上方法险领,直到需要加載的item都加載完成
- LayoutManager
用來定義RecyclerView的顯示規(guī)則(如定位列表項(xiàng)抖拦,定義屏幕的滾動(dòng)行為等),正因?yàn)橛蠰ayoutManager的存在舷暮,才使得RecyclerView顯示變得更靈活
- ViewHolder
ViewHolder在這里用來容納每個(gè)item里面的控件引用,然后執(zhí)行findViewById方法噩茄。因?yàn)閞ecyclerView里面的每個(gè)item都有相同的控件引用下面,所以使用ViewHolder之后就可以減少findViewById方法的調(diào)用從而提高性能。