这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识、前端、后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过!
RecyclerView侧重的是布局的灵活性,虽说可以替代ListView但是连基本的点击事件都没有,这篇文章就来详细讲解如何为RecyclerView的item添加点击事件,顺便复习一下观察者模式。
其实在 这篇文章 中已经提到如何实现,但是里面有很多不规范的地方,而且没有完整的代码。
最终目的
模拟ListView的setOnItemClickListener()方法,调用者只须调用类似于setOnItemClickListener的东西就能获得被点击item的相关数据。
原理
为RecyclerView的每个子item设置setOnClickListener,然后在onClick中再调用一次对外封装的接口,将这个事件传递给外面的调用者。而“为RecyclerView的每个子item设置setOnClickListener”在Adapter中设置。其实直接在onClick中也能完全处理item的点击事件,但是这样会破坏代码的逻辑。
步骤
adapter中
自定义一个继承自RecyclerView.Adapter的MyAdapter。
1.在MyAdapter中定义如下接口,模拟ListView的OnItemClickListener:
1. //define interface
2. public static interface OnItemClickListener {
3. void onItemClick(View view , int position);
4. }
声明一个这个接口的变量
- private OnItemClickListener mOnItemClickListener = null;
在onCreateViewHolder()中为每个item添加点击事件
1. @Override
2. public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
3. View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
4. ViewHolder vh = new ViewHolder(view);
5. //将创建的View注册点击事件
6. view.setOnClickListener(this);
7. return vh;
8. }
将点击事件转移给外面的调用者:
1. @Override
2. public void onClick(View v) {
3. if (mOnItemClickListener != null) {
4. //注意这里使用getTag方法获取position
5. mOnItemClickListener.onItemClick(v,(int)v.getTag());
6. }
7. }
注意上面调用接口的onItemClick()中的v.getTag()方法,这需要在onBindViewHolder()方法中设置和item的position
1. @Override
2. public void onBindViewHolder(ViewHolder viewHolder, int position) {
3. viewHolder.mTextView.setText(datas[position]);
4. //将position保存在itemView的Tag中,以便点击时进行获取
5. viewHolder.itemView.setTag(position);
6. }
最后暴露给外面的调用者,定义一个设置Listener的方法():
- public void setOnItemClickListener(OnItemClickListener listener) {
- this.mOnItemClickListener = listener;
- }
以上所有步骤都发生在自定义的adapter中,典型的观察者模式,有点绕的地方在于,这里涉及到两个观察者模式的使用,view的setOnClickListener本来就是观察者模式,我们将这个观察者模式的事件监听传递给了我们自己的观察者模式。
在Activity中使用
1. mRecyclerView = (RecyclerView)findViewById(R.id.my_recycler_view);
2. //创建默认的线性LayoutManager
3. mLayoutManager = new LinearLayoutManager(this);
4. mRecyclerView.setLayoutManager(mLayoutManager);
5. //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能
6. mRecyclerView.setHasFixedSize(true);
7. //创建并设置Adapter
8. mAdapter = new MyAdapter(data);
9. mRecyclerView.setAdapter(mAdapter);
10. mAdapter.setOnItemClickListener(new OnItemClickListener(){
11. @Override
12. public void onItemClick(View view , int position){
13. Toast.makeText(MainActivity.this, data[position], 600).show();
14. }
15. });
完整代码
MyAdapter.java
1. package com.example.recyclerviewdemo;
2.
3. import android.support.v7.widget.RecyclerView;
4. import android.util.Log;
5. import android.view.LayoutInflater;
6. import android.view.View;
7. import android.view.ViewGroup;
8. import android.widget.TextView;
9.
10. public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> implements View.OnClickListener{
11. private String[] datas;
12. public MyAdapter(String[] datas) {
13. this.datas = datas;
14. }
15. private OnItemClickListener mOnItemClickListener = null;
16.
17. //define interface
18. public static interface OnItemClickListener {
19. void onItemClick(View view , int position);
20. }
21.
22. @Override
23. public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
24. View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
25. ViewHolder vh = new ViewHolder(view);
26. //将创建的View注册点击事件
27. view.setOnClickListener(this);
28. return vh;
29. }
30.
31. @Override
32. public void onBindViewHolder(ViewHolder viewHolder, int position) {
33. viewHolder.mTextView.setText(datas[position]);
34. //将position保存在itemView的Tag中,以便点击时进行获取
35. viewHolder.itemView.setTag(position);
36. }
37.
38. @Override
39. public void onClick(View v) {
40. if (mOnItemClickListener != null) {
41. //注意这里使用getTag方法获取position
42. mOnItemClickListener.onItemClick(v,(int)v.getTag());
43. }
44. }
45.
46. public void setOnItemClickListener(OnItemClickListener listener) {
47. this.mOnItemClickListener = listener;
48. }
49.
50.
51. //获取数据的数量
52. @Override
53. public int getItemCount() {
54. return datas.length;
55. }
56. //自定义的ViewHolder,持有每个Item的的所有界面元素
57. public static class ViewHolder extends RecyclerView.ViewHolder {
58. public TextView mTextView;
59. public ViewHolder(View view){
60. super(view);
61. mTextView = (TextView) view.findViewById(R.id.text);
62. }
63. }
64. }
item.xml
1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2. xmlns:tools="http://schemas.android.com/tools"
3. android:layout_width="match_parent"
4. android:layout_height="50dip"
5. >
6. <TextView
7. android:id="@+id/text"
8. android:layout_width="wrap_content"
9. android:layout_height="wrap_content"
10. />
11. </RelativeLayout>
MainActivity.java
1. package com.example.recyclerviewdemo;
2.
3. import com.example.recyclerviewdemo.MyAdapter.OnItemClickListener;
4.
5. import android.support.v7.app.ActionBarActivity;
6. import android.support.v7.widget.LinearLayoutManager;
7. import android.support.v7.widget.RecyclerView;
8. import android.os.Bundle;
9. import android.view.Menu;
10. import android.view.MenuItem;
11. import android.view.View;
12. import android.widget.Toast;
13.
14. public class MainActivity extends ActionBarActivity {
15. private RecyclerView mRecyclerView;
16. private LinearLayoutManager mLayoutManager;
17. private MyAdapter mAdapter;
18. 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" };
19.
20. @Override
21. protected void onCreate(Bundle savedInstanceState) {
22. super.onCreate(savedInstanceState);
23. setContentView(R.layout.activity_main);
24. mRecyclerView = (RecyclerView)findViewById(R.id.my_recycler_view);
25. //创建默认的线性LayoutManager
26. mLayoutManager = new LinearLayoutManager(this);
27. mRecyclerView.setLayoutManager(mLayoutManager);
28. //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能
29. mRecyclerView.setHasFixedSize(true);
30. //创建并设置Adapter
31. mAdapter = new MyAdapter(data);
32. mRecyclerView.setAdapter(mAdapter);
33. mAdapter.setOnItemClickListener(new OnItemClickListener(){
34. @Override
35. public void onItemClick(View view , int position){
36. Toast.makeText(MainActivity.this, data[position], 600).show();
37. }
38. });
39. }
40.
41. @Override
42. public boolean onCreateOptionsMenu(Menu menu) {
43. // Inflate the menu; this adds items to the action bar if it is present.
44. getMenuInflater().inflate(R.menu.main, menu);
45. return true;
46. }
47.
48. @Override
49. public boolean onOptionsItemSelected(MenuItem item) {
50. // Handle action bar item clicks here. The action bar will
51. // automatically handle clicks on the Home/Up button, so long
52. // as you specify a parent activity in AndroidManifest.xml.
53. int id = item.getItemId();
54. if (id == R.id.action_settings) {
55. return true;
56. }
57. return super.onOptionsItemSelected(item);
58. }
59.
60.
61. }
activity_main.xml
1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2. xmlns:tools="http://schemas.android.com/tools"
3. android:layout_width="match_parent"
4. android:layout_height="match_parent"
5. tools:context=".MainActivity">
6. <android.support.v7.widget.RecyclerView
7. android:id="@+id/my_recycler_view"
8. android:layout_width="match_parent"
9. android:layout_height="match_parent"
10. android:scrollbars="vertical"/>
11. </RelativeLayout>
总结
在ListView中我们是调用ListView的setOnItemClickListener:
1. mListView.setOnItemClickListener(new OnItemClickListener() {
2. public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
3.
4. ...
5.
6. }
7. });
而在我们这里是调用mAdapter的setOnItemClickListener。