转载学习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的相关数据(这里只是一个字符串)。