Android RecyclerView单击、长按事件:基于OnItemTouchListener + GestureDetector标准实现
Android RecyclerView虽然拥有ListView绝大多数的功能,但Android RecyclerView却没有实现像ListView那样的点击事件、长按事件的标准实现方式,我在附录文章1中介绍的方式,实现了典型的RecyclerView的item点击事件,大致的思路是通过为RecyclerView的ViewHolder添加View.OnClickListener事件达到点击事件的监听,这种实现方式可以正常工作,但不太标准。现在给出一种较为规范的Android官方实现。
翻了Android RecyclerView的官方文档,这文档中确实没有提供像ListView的OnItem点击事件,但是注意到有一个addOnItemTouchListener,根据官方文档的描述,addOnItemTouchListener是Android官方文档中留下的点击事件的线索入口,文档中也暗示开发者应该从这个事件监听接口中实现所需的逻辑代码。但是直接new一个对象传递过去,则需要自己解析Android Touch Event复杂的处理,所幸Android官方给出了RecyclerView.SimpleOnItemTouchListener,顾名思义,就是一个简化的OnItemTouchListener。虽然有了SimpleOnItemTouchListener,到此还没完,因为SimpleOnItemTouchListener只是事件拦截处理的入口,真正要做事情的主角是:GestureDetector。通过GestureDetector里面的拦截到的所托管的单击、长按事件,才最终实现了RecyclerView的单击、长按事件。
完整代码:
package zhangphil.app; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private RecyclerView mRecyclerView; private GestureDetector mGestureDetector; //长按事件 private OnItemLongClickListener mOnItemLongClickListener = new OnItemLongClickListener() { @Override public void onItemLongClick(int position, View childView) { Toast.makeText(getApplication(), "长按:" + position, Toast.LENGTH_SHORT).show(); } }; //单击事件 private OnItemClickListener mOnItemClickListener = new OnItemClickListener() { @Override public void onItemClick(int position, View childView) { Toast.makeText(getApplication(), "单击:" + position, Toast.LENGTH_SHORT).show(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //创建一个简单的用以测试的RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView); LinearLayoutManager layoutManager = new LinearLayoutManager(this); layoutManager.setOrientation(LinearLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(layoutManager); mRecyclerView.setAdapter(new ItemAdapter()); //以下是添加点击、长按事件的关键代码 mRecyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { if (mGestureDetector.onTouchEvent(e)) { return true; } return false; } }); mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() { //长按事件 @Override public void onLongPress(MotionEvent e) { super.onLongPress(e); if (mOnItemLongClickListener != null) { View childView = mRecyclerView.findChildViewUnder(e.getX(), e.getY()); if (childView != null) { int position = mRecyclerView.getChildLayoutPosition(childView); mOnItemLongClickListener.onItemLongClick(position, childView); } } } //单击事件 @Override public boolean onSingleTapUp(MotionEvent e) { if (mOnItemClickListener != null) { View childView = mRecyclerView.findChildViewUnder(e.getX(), e.getY()); if (childView != null) { int position = mRecyclerView.getChildLayoutPosition(childView); mOnItemClickListener.onItemClick(position, childView); return true; } } return super.onSingleTapUp(e); } }); } //长按事件接口 public interface OnItemLongClickListener { public void onItemLongClick(int position, View childView); } //单击事件接口 public interface OnItemClickListener { public void onItemClick(int position, View childView); } private class ItemViewHolder extends RecyclerView.ViewHolder { public TextView text; public ItemViewHolder(View itemView) { super(itemView); text = (TextView) itemView.findViewById(android.R.id.text1); } } private class ItemAdapter extends RecyclerView.Adapter<ItemViewHolder> { @Override public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = View.inflate(parent.getContext(), android.R.layout.simple_list_item_1, null); ItemViewHolder holder = new ItemViewHolder(view); return holder; } @Override public void onBindViewHolder(ItemViewHolder holder, int position) { holder.text.setText(String.valueOf(position)); } @Override public int getItemCount() { return 99; } } }
因为我是在onInterceptTouchEvent里面拦截了RecyclerView的触摸事件,并通过GestureDetector
托管处理,由此可以延伸、进一步封装出更多更复杂的事件处理接口。
附录:
1,《RecyclerView点击事件》链接:http://blog.csdn.net/zhangphil/article/details/46771865