Search code examples
androidandroid-recyclerviewscrolltouch-event

Why RecyclerView still scrolls even after custom OnTouchListener implemented?


I know it might be a silly question but I need to know after I implement this code:

recyclerView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return false;
        }
    });

Why the recyclerView is still scrolling when the listener returns false? Or more precisely where is the scrolling behavior processed and handled?

I know that return true means the touch event is consumed and false means the touch event should get passed to the next view in view hierarchy. In my mind (which is possibly wrong), the return type shouldn't change the view behavior. Because when you don't process the onTouchListener, it means no touch event (including scrolling behavior) is processed so the recyclerView shouldn't be scrolling no matter the return type is true or false. What is wrong in my perception? I hope I'm clear enough.


Solution

  • I know that return true means the touch event is consumed and false means the touch event should get passed to the next view in view hierarchy

    This is not true, the correct order when a View handle a touch event is:

    • View.dispatchTouchEvent() will be called first

    • Sends event to View.OnTouchListener.onTouch() if exits

    • If not consumed, process View.onTouchEvent()

    In your case because your return false in View.OnTouchListener.onTouch(), it means you do not consume the event, so the event will be routed to View.onTouchEvent() of RecyclerView, which explains why the RecyclerView is still scrolling.

    Solution 1

    Return true in View.onTouchListener.onTouch() to show that the RecyclerView will consume all touch events.

    recyclerView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // I will consume all touch events,
            // so View.onTouchEvent() will not be called.
            return true;
        }
    });
    

    Solution 2

    Create a sub-class that extends from RecyclerView and return false in View.onTouchEvent() to show that the RecyclerView don't show interested in any touch event.

    public class MyRecyclerView extends RecyclerView {
    
        public MyRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent e) {
            // I don't show interested in any touch event.
            return false;
        }
    }
    

    This is a great presentation about Android Touch System, you should take a look.