7

I have a RecyclerView. Inside its adapter's onBindViewHolder() I set the OnClickListener to the ViewHolder's root layout.

However, I've recently noticed that I can't click on the RecyclerView's items while it's being scrolled. Only after it's stopped. If I click somewhere on the RecyclerView while I'm scrolling it, the RecyclerView only stops at that position, no items are clicked.

You can see what I mean inside the Gmail app. You can't open any email while you are scrolling its RecyclerView.

However, the Google Play app behaves differently. You can open app pages while scrolling the lists of apps. You can even scroll inner RecyclerViews horizontally while the parent RecyclerView is being scrolled.

Also I've noticed the same behaviour for a ScrollView. For example, if you put a lot of buttons inside it and begin to scroll it, the button listeners are not triggered. They can be triggered only after the ScrollView is stopped completely.

Do you have any idea how it's possible to achieve the behaviour like in the Google Play app? Thank you!

UltimateDevil
  • 2,807
  • 2
  • 18
  • 31
Sergiy
  • 221
  • 3
  • 11

4 Answers4

4

Here's a code written by Kimi Chiu in a related question:

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    boolean requestCancelDisallowInterceptTouchEvent = getScrollState() == SCROLL_STATE_SETTLING;
    boolean consumed = super.onInterceptTouchEvent(event);
    final int action = event.getActionMasked();

    switch (action) {
        case MotionEvent.ACTION_DOWN:
            if( requestCancelDisallowInterceptTouchEvent ){
                getParent().requestDisallowInterceptTouchEvent(false);
                // stop scroll to enable child view get the touch event
                stopScroll();
                // not consume the event
                return false;
            }
            break;
    }

    return consumed;
}

If you subclass the RecyclerView class and override this method, it will behave as in the question.

Sergiy
  • 221
  • 3
  • 11
1

Don't do this. Think about the user experience. You want to be able to allow users to scroll without them accidentally clicking to open new windows or details. Android users expect scrolling to prevent clicking. Once you stop, then you expect clicking to show details. You can certainly accomplish this if you want by overriding the onTouch and deciding how to handle the touch event if it is supplied to the recycler view or the row items, but I think you are creating a bad user experience. I tried the app store, it stops when you touch it as well Not sure what you meant by scrolling while open click or horizontal scroll because if I scroll vertically and then swipe left it just changes the page viewer.

So maybe not the answer you want, but I think User Experience is more important than "cool effect of touch while scrolling" management. If Android wanted that to be their OS experience it would be built in. Now this isn't the case for everything like swipable row items, but default master detail list handling is pretty standardized.

Sam
  • 5,342
  • 1
  • 23
  • 39
  • Hi Sam, thank you very much for your suggestion! You are right about the User Experience. I had some similar thoughts. However, in fact I need something similar to the Google Play app's viewpager. I didn't try to explain that in my original question, because it would complecate it. I have kinda 2-3 pages with RecyclerViews and I can't swipe between them freely when I'm stuck during some RecyclerView's scrolling process (it's possible to swipe to the next page only when the scrolling is completely stopped). So, I thought maybe someone has a prepared workaround for this case. – Sergiy Sep 29 '17 at 19:05
  • Oh gotcha, ok that makes more sense. Although, I have many apps that have pageviewers with nested recyclerviews and none of them prevent my from swiping between pages while flinging the list. So I'm not sure why yours would behave that way. So you are saying if you fling the list and then swipe it will ignore your swipe? – Sam Sep 29 '17 at 19:12
  • Hm, that's strange. Maybe I've done something wrong. Yes, you are right, in my case I have to wait before I can swipe to the next page... Also I have another part of the app where there is a ViewPager and each page is simply a ScrollView with several TextViews (like a tutorial). It also behaves that way. If I fling one page and try to swipe to the next page, I can't. I've tried the same on another phone with Android 4.1.2 (the first one has Android 7.0). It behaves the same way... – Sergiy Sep 29 '17 at 20:12
  • ok so that is different then. Are you dealing with scrollviews per pageview or recycler views? Does it work fine for recycler view pages, just not scrollview pages? – Sam Sep 29 '17 at 20:13
  • Well, there are two different Activities. One has a ViewPager with Fragments based on a RecyclerView. And another Activity has a ViewPager with Fragments based on a ScrollView. Both variants behave the same. If you start scrolling on a page and immediately try to swipe to the next page (like the initial scrolling is still in process), it can't swipe. – Sergiy Sep 29 '17 at 20:22
  • That is strange. I have never seen that behavior. I'm afraid I don't know how to help you as I wouldn't know how to repeat it without investing many hours trying lol. But best of luck and if you find out what it was, post your own answer so we can learn from it in case we ever hit that. I still think something is off though as I don't have this issue on any of my apps. So seems weird. – Sam Sep 29 '17 at 20:24
  • I've tried a couple of apps. It looks like most of them behave the same way... Other than Google Play, only Aliexpress can swipe freely, and only from the second page to the first one. So I guess there should be some workaround to achieve this free swiping :) – Sergiy Sep 29 '17 at 20:30
  • Okay Sam, I understand you. Thank you very much for trying to help me! – Sergiy Sep 29 '17 at 20:31
  • If anyone is reading this thread and is interested, you can subclass the ViewPager and override its `requestDisallowInterceptTouchEvent` method to make it empty. – Sergiy Oct 04 '17 at 16:28
0

You need to enable the "nested scrolling" flags inside of your scrolling parent. This is typically what you'd do if you want a horizontal scrolling recycler view inside of a vertical scrolling parent recycler view. You can do this for any scrolling view in general.

Amit Barjatya
  • 249
  • 3
  • 14
0

Only make the recyclerView react to click events when it is not scrolling:

if (recyclerView.scrollState == SCROLL_STATE_IDLE) {
    onItemClicked()
}
luckyhandler
  • 10,651
  • 3
  • 47
  • 64