这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是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.     }


声明一个这个接口的变量


  1.     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的方法():


  1.     public void setOnItemClickListener(OnItemClickListener listener) {
  2.         this.mOnItemClickListener = listener;
  3.     }


以上所有步骤都发生在自定义的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。