Android開發--RecyclerView使用,看AndroidL新特性,android5.0新特性
在去年Google I/0大會,Google開放了一個全新的視圖類RecyclerView,它被用來代替ListView以及GridView,提供更為高效的回收複用機制,同時實現管理與視圖的解耦合,今天對這個新的控制項來進行一次總結。
概述
首先,讓我們來看一下RecyclerView類之下都有哪些重要的類,以及他們的作用:
- RecyclerView.Adapter:管理的資料集合,為每個Item建立視圖;
- RecyclerView.ViewHolder:承載Item視圖的子視圖;
- RecyclerView.LayoutManager:負責Item視圖的布局;
- RecyclerView.ItemDecoration:為每個Item視圖添加子視圖,在Demo中被用來繪製Divider;
- RecyclerView.ItemAnimator:負責添加、刪除資料時的動畫效果;
基本用法
首先讓我來看一下RecyclerView的基本用法:
1.建立一個線性布局管理器LayoutManager
// 建立一個線性布局管理器mLayoutManager = new LinearLayoutManager(this);// 預設是Vertical,可以不寫mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);mRecyclerView.setLayoutManager(mLayoutManager);
2.重新一個adapter繼承RecyclerView.Adapter《VH》,VH就表示我們平時在ListView中用的ViewHolder類(該類必須繼承RecyclerView.ViewHolder);
在adapter中有幾個重要的方法需要我們自己補充:
- public int getItemCount():返回顯示Item總數;
- public void onBindViewHolder(ViewHolder vh, int position):綁定View到Item上vh就是我們在繼承RecyclerView.Adapter傳入的VH類型,在這個方法中處理資料顯示到Item上;
- public ViewHolder onCreateViewHolder(ViewGroup view, int position):在該方法中我們建立一個ViewHolder並返回,ViewHolder必須有一個帶有View的建構函式,這個View就是我們Item的根布局,在這裡我們可以自訂Item的布局;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private List<String> dataList; public MyAdapter(List<String> list) { this.dataList = list; } @Override public int getItemCount() { // TODO Auto-generated method stub return dataList.size(); } @Override public void onBindViewHolder(ViewHolder viewHolder, int position) { // TODO Auto-generated method stub viewHolder.textView.setText(dataList.get(position)); } @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) { // TODO Auto-generated method stub View view = LayoutInflater.from(viewGroup.getContext()).inflate( R.layout.item, null); ViewHolder holder = new ViewHolder(view); return holder; } public class ViewHolder extends RecyclerView.ViewHolder { public TextView textView; public ViewHolder(View view) { super(view); // TODO Auto-generated constructor stub textView = (TextView) view.findViewById(R.id.item_text); } }}
3.設定資料集
List<String> list = new ArrayList<String>();for (int i = 0; i < 100; i++) { list.add("item "+ i);}MyAdapter adapter = new MyAdapter(list);mRecyclerView.setAdapter(adapter);
改變LinearLayoutManager的方向可以設定為橫向的ListView顯示,這也是RecyclerView的強大之處,可以實現回收管理和視圖的解耦。
mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
如何為Item添加分割線
簡單的使用之後我們看到的RecyclerView連基本的分割線都沒有,接下來就來看看如何為它添加分割線吧:使用addItemDecoration方法可以為RecyclerView添加一個ItemDecoration,利用ItemDecoration為我們繪製分割線。
ItemDecoration下有三個方法,ItemDecoration並沒有對其實現,需要我們自己完成:
- onDraw方法:其繪製將會在每個Item被繪製之前進行;
- onDrawOver:在繪製完Item後進行繪製;
- getItemOffsets 可以通過outRect.set()為每個Item設定一定的位移量;
讓我們來看看代碼:
public class ItemDivider extends ItemDecoration { private Drawable mDrawable; public ItemDivider(Context context, int resId) { //在這裡我們傳入作為Divider的Drawable對象 mDrawable = context.getResources().getDrawable(resId); } @Override public void onDrawOver(Canvas c, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); //以下計算主要用來確定繪製的位置 final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDrawable.getIntrinsicHeight(); mDrawable.setBounds(left, top, right, bottom); mDrawable.draw(c); } } @Override public void getItemOffsets(Rect outRect, int position, RecyclerView parent) { outRect.set(0, 0, 0, mDrawable.getIntrinsicWidth()); }}
在這裡我寫了一個shape來代替分割線:
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#000" /> <size android:height="2dp" /></shape>
添加分割線的效果:
如何添加點擊事件 ##
在Adapter中設定自己OnItemClickListener以及OnItemLongClickListener
在ViewHolder中公開Item的根布局View,之後在onBindViewHolder方法獲得根布局View並設定點擊的listener,調用自己設定的listener
1.首先在MyAdapter中建立自己的介面:
public interface OnItemClickListener { public void onClick(View parent, int position);}public interface OnItemLongClickListener { public boolean onLongClick(View parent, int position);}
2.接著在ViewHolder中將根布局View公開:
public class ViewHolder extends RecyclerView.ViewHolder { public TextView textView; public View itemView; public ViewHolder(View view) { super(view); // TODO Auto-generated constructor stub itemView = view; textView = (TextView) view.findViewById(R.id.item_text); } }
3.最後在onBindViewHolder對itemView設定點擊事件:
viewHolder.itemView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if (onItemClickListener != null) { onItemClickListener.onClick(v, position); } } });viewHolder.itemView.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { // TODO Auto-generated method stub if (onItemLongClickListener != null) { return onItemLongClickListener.onLongClick(v, position); } return false; } });
如何判斷是否滑動到達尾部或頂部
LinearLayoutManager提供了如下幾個方法來協助開發人員擷取螢幕上的頂部item和底部item:
findFirstVisibleItemPosition()
findFirstCompletelyVisibleItemPosition()
findLastVisibleItemPosition()
findLastCompletelyVisibleItemPosition()
這樣我們就得到了思路:對RecyclerView設定滑動監聽事件,在其中進行判斷:
mRecyclerView.setOnScrollListener(new OnScrollListener() { boolean isShowTop = false; boolean isShowBottom = false; @Override public void onScrolled(int arg0, int arg1) { // TODO Auto-generated method stub if (mLayoutManager.findLastCompletelyVisibleItemPosition() == 99) { if (!isShowTop) { Toast.makeText(MainActivity.this, "滑動到底部", Toast.LENGTH_SHORT).show(); } isShowTop = true; } else { isShowTop = false; } if (mLayoutManager.findFirstCompletelyVisibleItemPosition() == 0) { if (!isShowBottom) { Toast.makeText(MainActivity.this, "滑動到頂部", Toast.LENGTH_SHORT).show(); } isShowBottom = true; } else { isShowBottom = false; } } @Override public void onScrollStateChanged(int arg0) { // TODO Auto-generated method stub }});
來看一下效果:
添加或移除資料
RecyclerView.Adapter中提供了兩個方法來做出添加資料或刪除資料的調整:
public final void notifyItemInserted(int position)
public final void notifyItemRemoved(int position)
這樣我們只需在自己的Adapter中提供添加或刪除的方法,並在方法之中調用上述方法即可:
public void insert(String data, int position){ dataList.add(position, data); notifyItemInserted(position); } public void remove(int position){ dataList.remove(position); notifyItemRemoved(position); }
接下來我在Activity中對RecyclerView設定點擊添加資料,長按刪除資料;
adapter.setOnItemClickListener(new OnItemClickListener() { @Override public void onClick(View parent, int position) { // TODO Auto-generated method stub adapter.insert("Insert", position); } }); adapter.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onLongClick(View parent, int position) { // TODO Auto-generated method stub adapter.remove(position); return true; } });
來看一下效果吧:
ItemAnimator可以設定載入和移除時的動畫,我們可以通過setItemAnimator方法設定,但目前只提供了DefaultItemAnimator。
源碼下載
點擊下載源碼