前三篇文章
android v7兼容包RecyclerView的使用(三)——布局管理器的使用
android v7兼容包RecyclerView的使用(二)
android v7兼容包RecyclerView的使用(一)
介绍了RecyclerView的使用以及常见的相关类和布局管理器的灵活之处。写了这么多篇,还没涉及到用户交互,那么怎么处理点击事件呢。
在RecyclerView中你会惊奇的发现,该类中并没有OnItemClickListener监听器监听我们的单击事件,也没有OnItemLongClickListener监听器监听我们的长按事件。取而代之的是OnItemTouchListener监听器,那么该怎样实现我们的点击事件和长按事件呢。
我们的代码是基于上篇文章布局管理器的代码,在其基础上加入事件监听。
假设让我们自己来事件点击事件,我们比方会使用ViewHolder来间接处理事件。首先在适配器中添加监听器接口。
- interface OnItemClickListener {
- void onClick(View v);
- }
-
- interface OnItemLongClickListener {
- void onLongClick(View v);
- }
-
- private OnItemClickListener onClickListener;
- private OnItemLongClickListener onLongClickListener;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
然后重载构造函数,使其能够接收监听器实例
- public CardViewAdapter(String[] data) {
- this(data, null, null);
- }
-
- public CardViewAdapter(String[] data, OnItemClickListener onClickListener) {
- this(data, onClickListener, null);
- }
-
- public CardViewAdapter(String[] data, OnItemClickListener onClickListener,
- OnItemLongClickListener onLongClickListener) {
- this.data = data;
- this.onClickListener = onClickListener;
- this.onLongClickListener = onLongClickListener;
- }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
终于会调用三參数的构造器,在该构造器内完毕赋值。
将原来的ViewHolder构造函数进行改造,使其处理点击事件,当然也能够直接在onCreateViewHolder函数里处理点击事件。
- public ViewHolder(View itemLayoutView,
- final OnItemClickListener onClickListener,
- final OnItemLongClickListener onLongClickListener) {
- super(itemLayoutView);
- info = (TextView) itemLayoutView.findViewById(R.id.info_text);
- itemLayoutView.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- //在监听器不为空的时候,进行回调
- if (onClickListener != null) {
- onClickListener.onClick(v);
- }
- }
- });
- itemLayoutView.setOnLongClickListener(new OnLongClickListener() {
-
- @Override
- public boolean onLongClick(View v) {
- //在监听器不为空的时候,进行回调
- if (onLongClickListener != null) {
- onLongClickListener.onLongClick(v);
- }
- //返回true,消费掉该事件,阻止其继续传递
- return true;
- }
- });
- }
- 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
细致一看,事实上代码还是挺多的,那么让我们调用一下。
- mAdapter = new CardViewAdapter(data,new OnItemClickListener() {
-
- @Override
- public void onClick(View v) {
- TextView info = (TextView) v.findViewById(R.id.info_text);
- Toast.makeText(getApplicationContext(), "单击"+info.getText(), Toast.LENGTH_LONG).show();
- }
- },new OnItemLongClickListener() {
-
- @Override
- public void onLongClick(View v) {
- TextView info = (TextView) v.findViewById(R.id.info_text);
- Toast.makeText(getApplicationContext(), "长按"+info.getText(), Toast.LENGTH_LONG).show();
-
- }
- });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
后面两个參数能够传空值,代表不设置监听器。
执行效果图例如以下。
我们会发现,上面的代码耦合性还是有点高,事件直接与适配器发生了耦合,除此之外,我们还应该有更好的方法来处理这个点击事件。是的,不是有OnItemTouchListener监听器吗,再配合手势不就能够吗。
好了,看代码吧,详解在凝视中。
- package cn.edu.zafu.layoutmanager;
-
- import android.content.Context;
- import android.support.v7.widget.RecyclerView;
- import android.view.GestureDetector;
- import android.view.MotionEvent;
- import android.view.View;
-
- /**
- * 监听器,实现OnItemTouchListener接口
- *
- * @author lizhangqu
- *
- * 2015-3-12
- */
- public class RecyclerItemClickListener implements
- RecyclerView.OnItemTouchListener {
- private OnItemClickListener mListener;
- private GestureDetector mGestureDetector;
-
- // 点击回调
- public interface OnItemClickListener {
- public void onItemClick(View view, int position);
-
- public void onItemLongClick(View view, int position);
- }
-
- public RecyclerItemClickListener(Context context,
- final RecyclerView recyclerView, OnItemClickListener listener) {
- mListener = listener;
- // 识别并处理手势
- mGestureDetector = new GestureDetector(context,
- new GestureDetector.SimpleOnGestureListener() {
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- // 轻击触摸屏后,弹起,必须返回true,否则无法触发单击
- return true;
- }
-
- @Override
- public void onLongPress(MotionEvent e) {
- // 长按
- // 依据findChildViewUnder(float x, float y)来算出哪个item被选择了
- View childView = recyclerView.findChildViewUnder(
- e.getX(), e.getY());
- // 有item被选则且监听器不为空触发长按事件
- if (childView != null && mListener != null) {
- mListener.onItemLongClick(childView,
- recyclerView.getChildPosition(childView));
- }
- }
- });
- }
-
- @Override
- public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
- View childView = view.findChildViewUnder(e.getX(), e.getY());
- if (childView != null && mListener != null
- && mGestureDetector.onTouchEvent(e)) {
- // 触发单击事件
- mListener.onItemClick(childView, view.getChildPosition(childView));
- return true;
- }
- return false;
- }
-
- @Override
- public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
- }
- }
- 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
- 65
- 66
- 67
- 68
- 69
- 70
在activity中调用
- mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getApplicationContext(), mRecyclerView, new OnItemClickListener() {
-
- @Override
- public void onItemLongClick(View view, int position) {
- Toast.makeText(getApplicationContext(), "长按"+data[position], Toast.LENGTH_SHORT).show();
- }
-
- @Override
- public void onItemClick(View view, int position) {
- Toast.makeText(getApplicationContext(), "短按"+data[position], Toast.LENGTH_SHORT).show();
- }
- }));
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
非常明显,另外一种方式与适配器进行了解耦。应该说优于第一种方法。
那么还有没有方法处理点击事件呢。让我们从万能的github上搜索一下。
https://github.com/lucasr/twoway-view
在该项目的sample文件夹下有个类里面有这样一段代码
- final ItemClickSupport itemClick = ItemClickSupport.addTo(mRecyclerView);
-
- itemClick.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(RecyclerView parent, View child, int position, long id) {
- mToast.setText("Item clicked: " + position);
- mToast.show();
- }
- });
-
- itemClick.setOnItemLongClickListener(new OnItemLongClickListener() {
- @Override
- public boolean onItemLongClick(RecyclerView parent, View child, int position, long id) {
- mToast.setText("Item long pressed: " + position);
- mToast.show();
- return true;
- }
- });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
上述代码有个ItemClickSupport 类,对的,该类就是提供事件的支持。那么该类在哪里呢,事实上它在该项目的core文件夹下。我直接将其该文件夹下的代码拷至我的项目的包中,删除一个不相关的类,就直接使用了,当然还须要拷一个资源文件就是ids.xml
实际执行效果呢,是跟上面两种方式是一样的,那么它的实现由什么差别呢,事实上与另外一种方式没什么大的差别,基本上就是OnItemTouchListener 加手势实现的,仅仅只是其逻辑可能更加严谨,设计更加优秀罢了。除此之外,该文件夹下另一个ItemSelectionSupport类,该类提供了item选择的功能,提供了单选多选方式,然而呢,在我測试时发现存在bug,所以呢,这个类的使用就跳过了。
至此,RecyclerView的点击事件就处理完了。