您的位置:首页 > 其它

从头开始学 RecyclerView(二) 添加item点击事件

2017-04-01 13:47 465 查看
不管了,先来张图



偶吐了个槽

item点击事件必须手动添加,默认并没有一个显式的API接口可供调用。

为了节约学习时间,网上找了篇很不错的文章。这里基本就复制了。

添加点击事件

RecyclerView#addOnItemTouchListener

分析

查看RecyclerView源码可以看到,RecyclerView预留了一个Item的触摸事件方法:

public void addOnItemTouchListener(OnItemTouchListener listener) {
mOnItemTouchListeners.add(listener);
}


通过注释我们可知,此方法是在滚动事件之前调用.需要传入一个OnItemTouchListener对象.OnItemTouchListener的代码如下:

public static interface OnItemTouchListener {

public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e);

public void onTouchEvent(RecyclerView rv, MotionEvent e);

public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);
}


此接口还提供了一个实现类,且官方推荐使用该实现类SimpleOnItemTouchListener,它就是一个空实现:

public static class SimpleOnItemTouchListener implements RecyclerView.OnItemTouchListener {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
return false;
}

@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}

@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}


在触摸接口中,当触摸时会回调一个MotionEvent对象,通过使用GestureDetectorCompat来解析用户的操作.

代码实现

RecyclerItemClickListener:

/**
* from http://blog.devwiki.net/index.php/2016/07/17/Recycler-View-Adapter-ViewHolder-optimized.html * 点击事件
* Created by DevWiki on 2016/7/16.
*/

public class RecyclerItemClickListener extends RecyclerView.SimpleOnItemTouchListener {
//public class RecyclerItemClickListener extends RecyclerView.OnItemTouchListener {

private OnItemClickListener clickListener;
//    private GestureDetector gestureDetector;
private GestureDetectorCompat gestureDetector; //v4 兼容包中

public interface OnItemClickListener {
/**
* 点击时回调
*
* @param view 点击的View
* @param position 点击的位置
*/
void onItemClick(View view, int position);

/**
* 长点击时回调
*
* @param view 点击的View
* @param position 点击的位置
*/
void onItemLongClick(View view, int position);
}

public RecyclerItemClickListener(final RecyclerView recyclerView, OnItemClickListener listener) {
this.clickListener = listener;
gestureDetector = new GestureDetectorCompat(recyclerView.getContext(),
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}

@Override
public void onLongPress(MotionEvent e) {
View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (childView != null && clickListener != null) {
clickListener.onItemLongClick(childView,
recyclerView.getChildAdapterPosition(childView));
}
}
});
}

@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View childView = rv.findChildViewUnder(e.getX(), e.getY());
if (childView != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onItemClick(childView, rv.getChildAdapterPosition(childView));
return true;
}
return false;
}
//
//    @Override
//    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
//
//    }
//
//    @Override
//    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
//
//    }
}


RV实现:

mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(mRecyclerView,
new RecyclerItemClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
System.out.println("onItemClick " + adapter.getItem(position));
}

@Override
public void onItemLongClick(View view, int position) {
System.out.println("onItemLongClick " + position);
}
}));


对ItemView添加点击监听

在adapter的bindCustomViewHolder()中,对holder.itemView添加监听

private static class ClickAdapter extends BaseAdapter<String, SimplifyVH> {

private RecyclerItemClickListener.OnItemClickListener mListener;

public ClickAdapter(Context context) {
super(context);
}

public ClickAdapter(Context context, List<String> list) {
super(context, list);
}

public void setListener(RecyclerItemClickListener.OnItemClickListener listener) {
mListener = listener;
}

@Override
public int getCustomViewType(int position) {
return 0;
}

@Override
public SimplifyVH createCustomViewHolder(ViewGroup parent, int viewType) {
return new SimplifyVH(
LayoutInflater.from(
parent.getContext()).inflate(R.layout.basic_simple, null, false));
}

@Override
public void bindCustomViewHolder(SimplifyVH holder, final int position) {

holder.itemView.setFocusable(true);//加了这句,电视上就能滚动了

TextView tvTitle = (TextView) holder.itemView.findViewById(R.id.tv_title);
tvTitle.setText(getItem(position));

View vImg = holder.itemView.findViewById(R.id.v_img);
vImg.setBackgroundColor(getColor());

final SimplifyVH vh = (SimplifyVH) holder;
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mListener != null) {
mListener.onItemClick(v, position);
}
}
});
vh.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mListener != null) {
mListener.onItemLongClick(v, position);
}
return true;
}
});
}
}


RV实现:

final ClickAdapter adapter = new ClickAdapter(this, mList);
adapter.setListener(new RecyclerItemClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
clickAnim(view);
System.out.println("onItemClick " + adapter.getItem(position));
}

@Override
public void onItemLongClick(View view, int position) {
System.out.println("onItemLongClick " + position);
}
});

mRecyclerView.setAdapter(adapter);


这种方式,在adaper中,定义一个listener;bind-viewHolder时,对itemView添加点击监听。

在adapter的createCustomViewHolder时,传入listener

在ViewHolder中关联一个listener

private static class SimplifyVH extends BaseHolder {

RecyclerItemClickListener.OnItemClickListener listener;

public SimplifyVH(ViewGroup parent, @LayoutRes int resId) {
super(parent, resId);
}

public SimplifyVH(View view, final RecyclerItemClickListener.OnItemClickListener listener) {
super(view);
this.listener = listener;
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onItemClick(v, getAdapterPosition());
}
}
});
view.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (listener != null) {
listener.onItemLongClick(v, getAdapterPosition());
}
return true;
}
});
}

}


相应的adaper实现:

private static class ClickAdapter3 extends BaseAdapter<String, SimplifyVHWithListener> {

private RecyclerItemClickListener.OnItemClickListener mListener;

public ClickAdapter3(Context context) {
super(context);
}

public ClickAdapter3(Context context, List<String> list) {
super(context, list);
}

public void setListener(RecyclerItemClickListener.OnItemClickListener listener) {
mListener = listener;
}

@Override
public int getCustomViewType(int position) {
return 0;
}

@Override
public SimplifyVHWithListener createCustomViewHolder(ViewGroup parent, int viewType) {
return new SimplifyVHWithListener(
LayoutInflater.from(
parent.getContext()).inflate(R.layout.basic_simple, null, false),
new RecyclerItemClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
clickAnim(view);
System.out.println("onItemClick " + getItem(position));
}

@Override
public void onItemLongClick(View view, int position) {
System.out.println("onItemLongClick " + position + "__" + getItem(position));
}
});
}

@Override
public void bindCustomViewHolder(SimplifyVHWithListener holder, final int position) {

holder.itemView.setFocusable(true);//加了这句,电视上就能滚动了

TextView tvTitle = (TextView) holder.itemView.findViewById(R.id.tv_title);
tvTitle.setText(getItem(position));

View vImg = holder.itemView.findViewById(R.id.v_img);
vImg.setBackgroundColor(getColor());
}
}


RV实现:

ClickAdapter3 adapter = new ClickAdapter3(this, mList);
mRecyclerView.setAdapter(adapter);


这种,跟前一个,只是写法上有区别,本质一样。都是对holder.itemview添加点击监听。这里在createCustomViewHolder内,初始化了RecyclerItemClickListener.OnItemClickListener,也可以直接使用mListener,由调用adapter时传入

当ItemView attach RecyclerView时实现

主要基于RecyclerView.OnChildAttachStateChangeListener。

public class ItemClickSupport {
private final RecyclerView mRecyclerView;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;

private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
}
};

private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mOnItemLongClickListener != null) {
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
return false;
}
};

private RecyclerView.OnChildAttachStateChangeListener mAttachListener
= new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(View view) {
if (mOnItemClickListener != null) {
view.setOnClickListener(mOnClickListener);
}
if (mOnItemLongClickListener != null) {
view.setOnLongClickListener(mOnLongClickListener);
}
}

@Override
public void onChildViewDetachedFromWindow(View view) {}
};

private ItemClickSupport(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
mRecyclerView.setTag(R.id.item_click_support, this);
mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}

public static ItemClickSupport addTo(RecyclerView view) {
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support == null) {
support = new ItemClickSupport(view);
}
return support;
}

public static ItemClickSupport removeFrom(RecyclerView view) {
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support != null) {
support.detach(view);
}
return support;
}

public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
mOnItemClickListener = listener;
return this;
}

public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
mOnItemLongClickListener = listener;
return this;
}

private void detach(RecyclerView view) {
view.removeOnChildAttachStateChangeListener(mAttachListener);
view.setTag(R.id.item_click_support, null);
}

public interface OnItemClickListener {
void onItemClicked(RecyclerView recyclerView, int position, View v);
}

public interface OnItemLongClickListener {
boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
}
}


RV实现:

final ClickAdapter1 adapter = new ClickAdapter1(this, mList);
mRecyclerView.setAdapter(adapter);
ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
System.out.println("onItem " + position + "  " + adapter.getItem(position));
}
}).setOnItemLongClickListener(new ItemClickSupport.OnItemLongClickListener() {
@Override
public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) {
System.out.println("onItemLongClick " + position);
return true;
}
});


三种方式对比

以上三种方式分别是:

通过RecyclerView已有的方法addOnItemTouchListener()实现

对holder.ItemView添加点击监听

当ItemView attach RecyclerView时实现

从以上三种方式的实现过程可知:

三种均可实现ItemView的点击事件和长按事件的监听.

第一种方式可以很方便获取用户点击的坐标. 但不支持TV上的click事件

第二种和第三种方式可以很方便对ItemView中的子View进行监听.

第一、三种方式可以写在单独的类中,相对于第二种可使代码更独立整洁

综上所述:

如果你想监听ItemView的点击事件或长按事件,三种方式均可.

如果你只想监听ItemView中每个子View的点击事件,采用第二种或者第三种比较方便.

如果想支持TV上的click事件,只能采用第二种或第三种

参考

http://blog.devwiki.net/index.php/2016/07/24/three-ways-click-recyclerview-item.html 《三种方式实现RecyclerView的Item点击事件》

http://www.littlerobots.nl/blog/Handle-Android-RecyclerView-Clicks/ 《Getting your clicks on RecyclerView》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: