如何将点击事件传递给 RecyclerView 的项目?
How to pass a click event to RecyclerView's items?
我有一个普通的 RecyclerView
,在它上面有一个实现 GestureListener
的透明 View
,它的大小基本上与 RecyclerView
相同。
GestureListener
将监听滚动和滑动手势,并将此 MotionEvent
传递给它下面的 RecyclerView
。
我已经让 RecyclerView
能够滚动和滑动。但是,我也找不到将点击事件传递给 RecyclerView
的 项 的方法。
我已经知道这是因为ACTION_DOWN
消耗在了GestureListener
。事实上,GestureListener
有一个 onSingleTap()
方法供您重写,每当我执行单击时都会调用此方法。
根据 this post,我尝试为我的 itemView 设置一个 OnTouchListener
并监听 ACTION_UP
事件。但是,从未调用 onTouch()
方法。
以下是我的做法:
1.在透明的GestureListener中创建一个回调
@Override
public boolean onSingleTapUp(MotionEvent e) {
if (scrollDetector == null) return false;
scrollDetector.onSingleTap(e);
return true;
}
在activity配置回调,将MotionEvent
传给RecyclerView
@Override
public void onSingleTap(MotionEvent e) {
mRecyclerView.onTouchEvent(e);
}
将OnTouchListener
设置为适配器中的itemView:
itemView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
v.performClick();
return true;
}
return false;
}
});
使用调试器,我可以看到调用了 mRecyclerView.onTouchEvent(e)
;但是没有调用itemView的onTouch()
所以...我应该如何正确地将 MotionEvent
传递给 itemView?
你可能会问 - "Why do you place a GestureListener on top of the RecyclerView?"
这是因为我需要在滚动 RecyclerView
时更改 RecyclerView
的高度。但是,如果我使用 RecyclerView
的 addOnScrollListener
执行此操作,dy
的值将在负值和正值之间波动,因为 dy 也受其高度影响。而且波动也会反映到UI.
因此,我需要一个滚动检测器,它在滚动时不会改变其高度,只需通过编程调用 scrollBy()
和 fling()
.
将滚动和滑动值传递给 RecyclerView
你应该知道recyclerview的event.Ifrecyclerview可以在滚动视图时移动,它会调用onInterceptTouchEvent()和return true拦截event.So你无法获得ACTION_MOVE event.Maybe 你应该重写 recyclerview 的 onInterceptTouchEvent() 和 return false。然后你可以在你的itemView的方法中得到所有的事件。
愚蠢的我。我应该使用 dispatchTouchEvent(MotionEvent e)
而不是 onTouchEvent(MotionEvent e)
.
然而,这还不够。
使用来自 GestureListener 的 MotionEvent 简单地调用 dispatchTouchEvent(e)
是行不通的,因为 e
是一个 ACTION_UP
事件。
要模拟点击,您需要 ACTION_DOWN
和 ACTION_UP
。
并且itemView不需要设置OnTouchListener
因为你已经模拟了
代码:
@Override
public void onSingleTap(MotionEvent e) {
long downTime = SystemClock.uptimeMillis();
long upTime = downTime + 100;
MotionEvent downEvent = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN,
e.getX(), e.getY(), 0);
mRecyclerView.dispatchTouchEvent(downEvent);
MotionEvent upEvent = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_UP,
e.getX(), e.getY(), 0);
mRecyclerView.dispatchTouchEvent(upEvent);
downEvent.recycle();
upEvent.recycle();
}
我有一个普通的 RecyclerView
,在它上面有一个实现 GestureListener
的透明 View
,它的大小基本上与 RecyclerView
相同。
GestureListener
将监听滚动和滑动手势,并将此 MotionEvent
传递给它下面的 RecyclerView
。
我已经让 RecyclerView
能够滚动和滑动。但是,我也找不到将点击事件传递给 RecyclerView
的 项 的方法。
我已经知道这是因为ACTION_DOWN
消耗在了GestureListener
。事实上,GestureListener
有一个 onSingleTap()
方法供您重写,每当我执行单击时都会调用此方法。
根据 this post,我尝试为我的 itemView 设置一个 OnTouchListener
并监听 ACTION_UP
事件。但是,从未调用 onTouch()
方法。
以下是我的做法:
1.在透明的GestureListener中创建一个回调
@Override
public boolean onSingleTapUp(MotionEvent e) {
if (scrollDetector == null) return false;
scrollDetector.onSingleTap(e);
return true;
}
在activity配置回调,将
MotionEvent
传给RecyclerView
@Override public void onSingleTap(MotionEvent e) { mRecyclerView.onTouchEvent(e); }
将
OnTouchListener
设置为适配器中的itemView:itemView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { v.performClick(); return true; } return false; } });
使用调试器,我可以看到调用了 mRecyclerView.onTouchEvent(e)
;但是没有调用itemView的onTouch()
所以...我应该如何正确地将 MotionEvent
传递给 itemView?
你可能会问 - "Why do you place a GestureListener on top of the RecyclerView?"
这是因为我需要在滚动 RecyclerView
时更改 RecyclerView
的高度。但是,如果我使用 RecyclerView
的 addOnScrollListener
执行此操作,dy
的值将在负值和正值之间波动,因为 dy 也受其高度影响。而且波动也会反映到UI.
因此,我需要一个滚动检测器,它在滚动时不会改变其高度,只需通过编程调用 scrollBy()
和 fling()
.
RecyclerView
你应该知道recyclerview的event.Ifrecyclerview可以在滚动视图时移动,它会调用onInterceptTouchEvent()和return true拦截event.So你无法获得ACTION_MOVE event.Maybe 你应该重写 recyclerview 的 onInterceptTouchEvent() 和 return false。然后你可以在你的itemView的方法中得到所有的事件。
愚蠢的我。我应该使用 dispatchTouchEvent(MotionEvent e)
而不是 onTouchEvent(MotionEvent e)
.
然而,这还不够。
使用来自 GestureListener 的 MotionEvent 简单地调用 dispatchTouchEvent(e)
是行不通的,因为 e
是一个 ACTION_UP
事件。
要模拟点击,您需要 ACTION_DOWN
和 ACTION_UP
。
并且itemView不需要设置OnTouchListener
因为你已经模拟了
代码:
@Override
public void onSingleTap(MotionEvent e) {
long downTime = SystemClock.uptimeMillis();
long upTime = downTime + 100;
MotionEvent downEvent = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN,
e.getX(), e.getY(), 0);
mRecyclerView.dispatchTouchEvent(downEvent);
MotionEvent upEvent = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_UP,
e.getX(), e.getY(), 0);
mRecyclerView.dispatchTouchEvent(upEvent);
downEvent.recycle();
upEvent.recycle();
}