Android RecyclerView的使用

yangxi_001發表於2016-03-11

RecyclerView是android5.0提供的新元件(最新的support.v7中也提供了該元件),類似於ListView,但是比ListView更靈活、更先進,我覺得主要表現在以下幾個方面:

1、 把ViewHolder的實現封裝起來,規範了ViewHolder,把item的view寫入ViewHolder中,通過複用ViewHolder來實現view的複用。

2、 RecyclerView.Adapter中把view的回收和內容改變等操作分開解耦了,比傳統的Adapter更為靈活。

3、 獨立的LayoutManager,可以靈活的控制RecyclerView中items的佈局:LinearLayoutManager(垂直佈局、水平佈局)、GridLayoutManager(網格佈局)、StaggeredGridLayoutManager(瀑布流佈局);

4、 提供了RecyclerView.ItemAnimator可以設定items增加、刪除時的動畫(預設已有定義了動畫);

 

下面通過官方例子來看一下RecyclerView的使用。

1、 佈局檔案xml的編寫,沒什麼好說的。

 

1.<android.support.v7.widget.RecyclerView
2.android:id="@+id/my_recycler_view"
3.android:scrollbars="vertical"
4.android:layout_width="match_parent"
5.android:layout_height="match_parent"/>

 

2、在activity中使用RecyclerView

01.public class MyActivity extends Activity {
02.private RecyclerView mRecyclerView;
03.private RecyclerView.Adapter mAdapter;
04.private RecyclerView.LayoutManager mLayoutManager;
05. 
06.@Override
07.protected void onCreate(Bundle savedInstanceState) {
08.super.onCreate(savedInstanceState);
09.setContentView(R.layout.my_activity);
10.mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
11. 
12.// use this setting to improve performance if you know that changes
13.// in content do not change the layout size of the RecyclerView
14.mRecyclerView.setHasFixedSize(true);
15. 
16.// use a linear layout manager
17.mLayoutManager = new LinearLayoutManager(this);
18.mRecyclerView.setLayoutManager(mLayoutManager);
19. 
20.// specify an adapter (see also next example)
21.mAdapter = new MyAdapter(myDataset);
22.mRecyclerView.setAdapter(mAdapter);
23.}
24....
25.}

程式碼很簡單,看一下我們使用到RecyclerView的幾個地方:首先是mRecyclerView.setHasFixedSize(true),從上面的註釋可以知道,如果item的內容不改變view佈局大小,那使用這個設定可以提高RecyclerView的效率。接著再看mLayoutManager = new LinearLayoutManager(this);mRecyclerView.setLayoutManager(mLayoutManager),這裡就使用LayoutManager來控制item的排列方式,這裡用的是LinearLayoutManager,也就是線性佈局,預設是垂直佈局,如果要設定成水平佈局,只需在把new LinearLayoutManager(this)改成newLinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false)就可以了,最後一項如果為true的話,item會反向排列。

3、編寫Adapter

01.public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
02.private String[] mDataset;
03. 
04.// Provide a reference to the views for each data item
05.// Complex data items may need more than one view per item, and
06.// you provide access to all the views for a data item in a view holder
07.public static class ViewHolder extends RecyclerView.ViewHolder {
08.// each data item is just a string in this case
09.public TextView mTextView;
10.public ViewHolder(TextView v) {
11.super(v);
12.mTextView = v;
13.}
14.}
15. 
16.// Provide a suitable constructor (depends on the kind of dataset)
17.public MyAdapter(String[] myDataset) {
18.mDataset = myDataset;
19.}
20. 
21.// Create new views (invoked by the layout manager)
22.@Override
23.public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
24.int viewType) {
25.// create a new view
26.View v = LayoutInflater.from(parent.getContext())
27..inflate(R.layout.my_text_view, parent, false);
28.// set the view's size, margins, paddings and layout parameters
29....
30.ViewHolder vh = new ViewHolder(v);
31.return vh;
32.}
33. 
34.// Replace the contents of a view (invoked by the layout manager)
35.@Override
36.public void onBindViewHolder(ViewHolder holder, int position) {
37.// - get element from your dataset at this position
38.// - replace the contents of the view with that element
39.holder.mTextView.setText(mDataset[position]);
40. 
41.}
42. 
43.// Return the size of your dataset (invoked by the layout manager)
44.@Override
45.public int getItemCount() {
46.return mDataset.length;
47.}
48.}

首先看一下ViewHolder,這裡不再是自己隨便定義的ViewHolder了,而是繼承了RecyclerView.ViewHolder,規範了ViewHolder。不同於傳統的Adapter,這裡沒有getView,取而代之的是onCreateViewHolder和onBindViewHolder,把view的複用和資料的繫結解耦開了。

 

上面就是官方的簡單例子,接下來我們來實現兩個比較常用的功能,item的點選和上拉載入。

 

RecyclerView並沒有提供item的點選事件,這也讓我們有了多種實現方式,不管什麼方式,歸根到底就是對view的點選事件。我們可以在Adapter中新增對view的點選事件,有兩個地方可以新增,大家看哪種方法更好。

1、 在ViewHolder中新增。

 

01.public static class ViewHolder extends RecyclerView.ViewHolder {
02.// each data item is just a string in this case
03.public TextView mTextView;
04.public ViewHolder(TextView v) {
05.super(v);
06.mTextView = v;
07.v. setOnClickListener….
08.}
09.}


 


2、 在onBindViewHolder中新增。

 

1.@Override
2.public void onBindViewHolder(ViewHolder holder, int position) {
3.// - get element from your dataset at this position
4.// - replace the contents of the view with that element
5.holder.mTextView.setText(mDataset[position]);
6.holder.itemView.setOnClickListener…;
7.}


 

再來看看上拉載入更多,我覺得最好的方法就是在onBindViewHolder新增對上拉載入事件的判斷,因為如果用傳統的監聽scroll的方法來做的話,那麼如果我改變了LayoutManager,從垂直線性佈局改成水平線性佈局,或者從線性佈局改成網格佈局,那麼對scroll監聽的方法又得重新寫了。下面看下具體的寫法。

 

1.@Override
2.public void onBindViewHolder(ViewHolder holder, int position) {
3.if (position == list.size() - 1&&onLoadListener!=null&&(list.size()%limit)==0) {
4.onLoadListener.load();
5.Log.i("zhuang","觸發");
6.}
7.}

 

如果當前繫結的ViewHolder的position是最後一項,則觸發載入更多。這裡的onLoadListener是我自定義載入介面

1.public interface OnLoadListener {
2.public void load();
3.}

在Adapter中定義OnLoadListener變數,然後生成get和set方法,我們在activity中可以通過adapter.setOnLoadListener來為載入更多設定載入的具體實現。(list.size()%limit)==0)中的limit是每次載入的item數量,如果list.size()%limit)==0,表示每次從伺服器載入的item數和我們請求的item數是一樣的,證明還有其他記錄,再次把list拉到最後面的item時,我們可以繼續觸發load方法,如果list.size()%limit)!=0,則說明我們從伺服器載入過來的item數和我們請求的item數不一樣,那麼證明資料已經全部都載入完了,沒必要再次請求了,就算list拉到最後一項,也不再請求。當然還有一種情況就是載入的資料數和我們請求的資料數是一樣的,而剛好也請求完所有資料,這時候我們上拉到最後一項時,還會再觸發一次載入。

下面貼上稍微完整的程式碼

OnLoadListener:

1.public interface OnLoadListener {
2.public void load();
3.}

MyActivity

01.public class MyActivity extends Activity {
02.private RecyclerView mRecyclerView;
03.private RecyclerView.Adapter mAdapter;
04.private RecyclerView.LayoutManager mLayoutManager;
05.private String[] myDataset = {...};
06. 
07.@Override
08.protected void onCreate(Bundle savedInstanceState) {
09.super.onCreate(savedInstanceState);
10.setContentView(R.layout.my_activity);
11.mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
12. 
13.// use this setting to improve performance if you know that changes
14.// in content do not change the layout size of the RecyclerView
15.mRecyclerView.setHasFixedSize(true);
16. 
17.// use a linear layout manager
18.mLayoutManager = new LinearLayoutManager(this);
19.mRecyclerView.setLayoutManager(mLayoutManager);
20. 
21.// specify an adapter (see also next example)
22.mAdapter = new MyAdapter(myDataset,limit);
23.mAdapter.setOnLoadListener(new OnLoadListener() {
24.@Override
25.public void load() {
26....
27.}
28.});
29.mRecyclerView.setAdapter(mAdapter);
30. 
31.}
32....
33.}

MyAdapter:

01.public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
02.private String[] mDataset;
03.private OnLoadListener onLoadListener;
04.private int limit;
05. 
06.// Provide a reference to the views for each data item
07.// Complex data items may need more than one view per item, and
08.// you provide access to all the views for a data item in a view holder
09.public static class ViewHolder extends RecyclerView.ViewHolder {
10.// each data item is just a string in this case
11.public TextView mTextView;
12.public ViewHolder(TextView v) {
13.super(v);
14.mTextView = v;
15.}
16.}
17. 
18.// Provide a suitable constructor (depends on the kind of dataset)
19.public MyAdapter(String[] myDataset,int limit) {
20.this.mDataset = myDataset;
21.this.limit = limit;
22.}
23. 
24.// Create new views (invoked by the layout manager)
25.@Override
26.public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
27.int viewType) {
28.// create a new view
29.View v = LayoutInflater.from(parent.getContext())
30..inflate(R.layout.my_text_view, parent, false);
31.// set the view's size, margins, paddings and layout parameters
32....
33.ViewHolder vh = new ViewHolder(v);
34.return vh;
35.}
36. 
37.// Replace the contents of a view (invoked by the layout manager)
38.@Override
39.public void onBindViewHolder(ViewHolder holder, int position) {
40.// - get element from your dataset at this position
41.// - replace the contents of the view with that element
42.holder.mTextView.setText(mDataset[position]);
43.holder.itemView.setOnClickListener(...);
44.if (position == list.size() - 1&&onLoadListener!=null&&(list.size()%limit)==0) {
45.onLoadListener.load();
46.Log.i("zhuang","觸發");
47.}
48. 
49. 
50.}
51. 
52.// Return the size of your dataset (invoked by the layout manager)
53.@Override
54.public int getItemCount() {
55.return mDataset.length;
56.}
57.}

相關文章