轉載學習http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0327/2647.html
最終目的
模擬ListView的setOnItemClickListener()方法,調用者只須調用類似於setOnItemClickListener的東西就能獲得被點擊item的相關數據。
原理
爲RecyclerView的每個子item設置setOnClickListener,然後在onClick中再調用一次對外封裝的接口,將這個事件傳遞給外面的調用者。而“爲RecyclerView的每個子item設置setOnClickListener”在Adapter中設置。其實直接在onClick中也能完全處理item的點擊事件,但是這樣會破壞代碼的邏輯。
步驟
adapter中
自定義一個繼承自RecyclerView.Adapter的MyAdapter。
1.在MyAdapter中定義如下接口,模擬ListView的OnItemClickListener:
1
2
3
4
|
//define interface public static interface OnRecyclerViewItemClickListener { void onItemClick(View view , String data); } |
聲明一個這個接口的變量
1
|
private OnRecyclerViewItemClickListener mOnItemClickListener = null ; |
在onCreateViewHolder()中爲每個item添加點擊事件
1
2
3
4
5
6
7
8
|
@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); //將創建的View註冊點擊事件 view.setOnClickListener( this ); return vh; } |
將點擊事件轉移給外面的調用者:
1
2
3
4
5
6
7
|
@Override public void onClick(View v) { if (mOnItemClickListener != null ) { //注意這裏使用getTag方法獲取數據 mOnItemClickListener.onItemClick(v,(String)v.getTag()); } } |
注意上面調用接口的onItemClick()中的v.getTag()方法,這需要在onBindViewHolder()方法中設置和item相關的數據
1
2
3
4
5
6
|
@Override public void onBindViewHolder(ViewHolder viewHolder, int position) { viewHolder.mTextView.setText(datas[position]); //將數據保存在itemView的Tag中,以便點擊時進行獲取 viewHolder.itemView.setTag(datas[position]); } |
最後暴露給外面的調用者,定義一個設置Listener的方法():
1
2
3
|
public void setOnItemClickListener(OnRecyclerViewItemClickListener listener) { this .mOnItemClickListener = listener; } |
以上所有步驟都發生在自定義的adapter中,典型的觀察者模式,有點繞的地方在於,這裏涉及到兩個觀察者模式的使用,view的setOnClickListener本來就是觀察者模式,我們將這個觀察者模式的事件監聽傳遞給了我們自己的觀察者模式。
在Activity中使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
mRecyclerView = (RecyclerView)findViewById(R.id.my_recycler_view); //創建默認的線性LayoutManager mLayoutManager = new LinearLayoutManager( this ); mRecyclerView.setLayoutManager(mLayoutManager); //如果可以確定每個item的高度是固定的,設置這個選項可以提高性能 mRecyclerView.setHasFixedSize( true ); //創建並設置Adapter mAdapter = new MyAdapter(data); mRecyclerView.setAdapter(mAdapter); mAdapter.setOnItemClickListener( new OnRecyclerViewItemClickListener(){ @Override public void onItemClick(View view , String data){ Toast.makeText(MainActivity. this , data, 600).show(); } }); |
完整代碼
MyAdapter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
package com.example.recyclerviewdemo; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> implements View.OnClickListener{ private String[] datas; public MyAdapter(String[] datas) { this .datas = datas; } private OnRecyclerViewItemClickListener mOnItemClickListener = null ; //define interface public static interface OnRecyclerViewItemClickListener { void onItemClick(View view , String data); } @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); //將創建的View註冊點擊事件 view.setOnClickListener( this ); return vh; } @Override public void onBindViewHolder(ViewHolder viewHolder, int position) { viewHolder.mTextView.setText(datas[position]); //將數據保存在itemView的Tag中,以便點擊時進行獲取 viewHolder.itemView.setTag(datas[position]); } @Override public void onClick(View v) { if (mOnItemClickListener != null ) { //注意這裏使用getTag方法獲取數據 mOnItemClickListener.onItemClick(v,(String)v.getTag()); } } public void setOnItemClickListener(OnRecyclerViewItemClickListener listener) { this .mOnItemClickListener = listener; } //獲取數據的數量 @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); } } } |
item.xml
1
2
3
4
5
6
7
8
9
10
11
|
<RelativeLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:layout_width= "match_parent" android:layout_height= "50dip" > <TextView android:id= "@+id/text" android:layout_width= "wrap_content" android:layout_height= "wrap_content" /> </RelativeLayout> |
MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
package com.example.recyclerviewdemo; import com.example.recyclerviewdemo.MyAdapter.OnRecyclerViewItemClickListener; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; public class MainActivity extends ActionBarActivity { private RecyclerView mRecyclerView; private LinearLayoutManager mLayoutManager; private MyAdapter mAdapter; private String[] data= new String[] { "aa" , "bb" , "aa" , "bb" , "aa" , "bb" , "aa" , "bb" , "aa" , "bb" , "aa" , "bb" , "aa" , "bb" , "aa" , "bb" , "aa" , "bb" , "aa" , "bb" }; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = (RecyclerView)findViewById(R.id.my_recycler_view); //創建默認的線性LayoutManager mLayoutManager = new LinearLayoutManager( this ); mRecyclerView.setLayoutManager(mLayoutManager); //如果可以確定每個item的高度是固定的,設置這個選項可以提高性能 mRecyclerView.setHasFixedSize( true ); //創建並設置Adapter mAdapter = new MyAdapter(data); mRecyclerView.setAdapter(mAdapter); mAdapter.setOnItemClickListener( new OnRecyclerViewItemClickListener(){ @Override public void onItemClick(View view , String data){ Toast.makeText(MainActivity. this , data, 600).show(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true ; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true ; } return super .onOptionsItemSelected(item); } } |
activity_main.xml
1
2
3
4
5
6
7
8
9
10
11
|
<RelativeLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:layout_width= "match_parent" android:layout_height= "match_parent" tools:context= ".MainActivity" > <android.support.v7.widget.RecyclerView android:id= "@+id/my_recycler_view" android:layout_width= "match_parent" android:layout_height= "match_parent" android:scrollbars= "vertical" /> </RelativeLayout> |
總結
在ListView中我們是調用ListView的setOnItemClickListener:
1
2
3
4
5
6
7
|
mListView.setOnItemClickListener( new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { ... } }); |
而在我們這裏是調用mAdapter的setOnItemClickListener。且回調方法public void onItemClick()的參數也不一致,ListView中有被點擊item的position參數,而我們這裏直接是被點擊item的相關數據(這裏只是一個字符串)。