1

I have an ordinary RecyclerView, and on top of it a transparent View that implements GestureListener, which basically have the same size of the RecyclerView.

The GestureListener will listen to scroll and fling gestures, and pass this MotionEvent to the RecyclerView underneath it.

I have already made the RecyclerView able to scroll and fling. However, I can't find a way to pass a click event down to the RecyclerView's items as well.

I already know that this is because ACTION_DOWN is consumed in the GestureListener. In fact, GestureListener has a onSingleTap() method for you to override, and this method was called whenever I perform a click.

According to this post, I tried to set an OnTouchListener to my itemView and listen to ACTION_UP events. However, the onTouch() method is never called.

Below is how I do it:
1. Create a callback in the transparent GestureListener

 @Override public boolean onSingleTapUp(MotionEvent e) { if (scrollDetector == null) return false; scrollDetector.onSingleTap(e); return true; } 
  1. Configure the callback in the activity, and pass the MotionEvent to the RecyclerView

    @Override public void onSingleTap(MotionEvent e) { mRecyclerView.onTouchEvent(e); } 
  2. Set OnTouchListener to the itemView in the adapter:

    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; } }); 

Using debugger, I can see that mRecyclerView.onTouchEvent(e) was called; but the onTouch() of itemView was not called.

So... How should I correctly pass the MotionEvent to the itemView?

You may ask - "Why do you place a GestureListener on top of the RecyclerView?"
This is because I need to change the height of the RecyclerView when the RecyclerView is scrolled. However, if I do this using RecyclerView's addOnScrollListener, the value of dy will fluctuate between negative and positive values, because dy is affected by its height as well. And the fluctuation will also be reflected to the UI.
Therefore I need a scroll detector that does not change its height when scrolled, and just pass the scroll and fling values to RecyclerView by programmatically calling scrollBy() and fling().

2 Answers 2

0

You should known that recyclerview's event.If recyclerview can move when you scroll views,it will call onInterceptTouchEvent() and return true to intercept event.So you can't get the ACTION_MOVE event.Maybe you should rewrite the recyclerview's onInterceptTouchEvent() and return false. Then you can get all the event in your itemView's methods.

Sign up to request clarification or add additional context in comments.

Comments

0

Stupid me. I should use dispatchTouchEvent(MotionEvent e) instead of onTouchEvent(MotionEvent e).

However, this is not enough.
Simply calling dispatchTouchEvent(e) using the MotionEvent from GestureListener is not working, because that e is an ACTION_UP event.

To simulate a click, you need both ACTION_DOWN and ACTION_UP.

And itemView does not need to set OnTouchListener since you have already simulate

Code:

 @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(); } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.