30

I just upgraded to API 26 and support library 26.0.2. But I found that my RecyclerView items is not clickable right after the scrolling. If you wait for a second, it will work. But if you click the item immediately, it won't. Even if the RecyclerView is not scrolling at all(e.g. has scrolled to the top).

When I downgraded to support library 25.4.0 everything goes fine again. The key point is that my RecyclerView is in a CoordinatorLayout and has a SCROLL_FLAG_SCROLL flag on my Toolbar of the AppBarLayout. If I don't use this flag, then this problem will disappear. So I think it's a hidden behavior change of support library 26.

I've tried to add focusable="false" to the CoordinatorLayout but still had no luck.

Is there any way to disable this behavior? Because it's really annoying to click twice to trigger the click event.

 <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinateLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
            android:id="@+id/fragmentAppBar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:elevation="0dp"
            android:background="@null">
        <include
                android:id="@+id/dynamicActionBarHolder"
                layout="@layout/dynamic_action_bar"/>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/pullToRefreshMailRecycler"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.v7.widget.RecyclerView
                android:id="@+id/mailRecyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>

    </android.support.v4.widget.SwipeRefreshLayout>

</android.support.design.widget.CoordinatorLayout>

EDIT

I think the problem is the scrollState of the RecyclerView. When it's stopped scrolling, it's not changed to SCROLL_STATE_IDLE immediately. Looking into the source code of RecyclerView, I found there's a ViewFlinger controlling the scroll state. When I fling down to scroll to the top, it's not calling setScrollState(SCROLL_STATE_IDLE) immediately, instead, it wait for a while to trigger this method. The more fast I fling, the more time I need to wait. It just like the RecyclerView is still scrolling in the background. Because the scroller.isFinished() doesn't return true right after the RecyclerView stop scrolling when it touched the top. Maybe it's a bug of the RecyclerView when it's in a CoordinatorLayout.

Kimi Chiu
  • 2,103
  • 3
  • 22
  • 37

3 Answers3

42

Found a way to force the scroll state to be idle. Waiting for google to fix this bug.

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

                // only if it touched the top or the bottom. Thanks to @Sergey's answer.
                if (!canScrollVertically(-1) || !canScrollVertically(1)) {
                    // stop scroll to enable child view to get the touch event
                    stopScroll();
                    // do not consume the event
                    return false;
                }
            }
            break;
    }

    return consumed;
}

EDIT

The issue has been fixed in support library 27.0.1.

https://developer.android.com/topic/libraries/support-library/revisions.html#27-0-1

After a user scrolls, they cannot click on an item in a RecyclerView. (AOSP issue 66996774)

Updated on Nov 17, 2017

Some users reported that this problem is not fixed in support library 27.0.1. The issue tracker is here. https://issuetracker.google.com/issues/66996774

So you may choose to use this official workaround. https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2

Or use this one here.

Kimi Chiu
  • 2,103
  • 3
  • 22
  • 37
  • 1
    `The issue has been fixed in support library 27.0.1.` this doesn't actually fix it for me at all :P 27.0.2 (haven't had the time for the workarounds yet) – EpicPandaForce Feb 21 '18 at 17:03
  • @EpicPandaForce We all knew that Google is not good at fixing bugs. I'm still waiting for them to fix the chromium bug which makes my app crashed 200 times a day. And it's been almost a year. – Kimi Chiu Feb 22 '18 at 05:31
  • Not good at fixing bugs isnt the problem, developers did fix it manually. The problem is Google is also good at creating bugs. You know, Im afraid-ed to updating Google's API. – nyconing Jun 05 '18 at 07:19
  • @nyconing Totally agree with you. It's always a disaster. – Kimi Chiu Jun 05 '18 at 15:49
  • I'm not using Coordinate layout and AppBarLayout, Having horizontal recylerview inside Relativelayout. I have a requirement, as the recylerview need to scroll automatically, need to find the center item in screen, also need to click the items while scrolling. I have achieved auto scrolling. But click on items not working. I have raised a question here, https://stackoverflow.com/questions/51959211/item-click-is-not-working-while-auto-scroll-in-recyclerview – Manikandan Aug 22 '18 at 06:48
  • @KimiChiu you deserve a 1000 thumbs up.. I just override onInterceptTouchEvent of my recyclerview with your solution and it worked like a charm.. cheers to you! – Bassel Mourjan Oct 12 '18 at 08:12
  • Issue is still present in androidX as well. – Usman Rana May 15 '19 at 08:13
  • Can someone tell me how to use this code? I have a horizontal recyclerview inside a vertical recyclerview, which is inside a Nestedscrollview. I suppose I have to subclass the parent recyclerview and override this method. Please tell me if that's not how it needs to be done. – Harsha Vardhan Jun 11 '19 at 05:19
5

Thank you very much for this question and your answer! It saved me a lot of time. Sorry for posting this as an answer. I don't have enough reputation to comment.

I also noticed this issue, but as a new Android developer I didn't realize it's a bug inside the new support library.

What I wanted to suggest is also adding this check:

if( requestCancelDisallowInterceptTouchEvent ){
    if (!canScrollVertically(-1) || !canScrollVertically(1)) {
        ...
    }
}

It will make sure that while the RecyclerView is actually being scrolled, we don't click on any item.

As I understand, it's an expected behaviour. However, your answer helped me with this question.

Sergiy
  • 221
  • 3
  • 11
  • You're right. I'm using `findFirstCompletelyVisibleItemPosition` and `findLastCompletelyVisibleItemPosition` of the `LayoutManager` to check if my `RecyclerView` is already scrolled to the top or to the bottom. Didn't know there's a `canScrollVertically` method. This is way more elegant than using `LayoutManager`. – Kimi Chiu Oct 05 '17 at 04:33
  • Hi @KimiChiu! Once again, I could only comment to my answer :) Hey! It looks like they have fixed this bug inside the Revision 27.0.1. And I bet it was your report https://issuetracker.google.com/issues/66996774 :)) At least the email starts with "ki...@gmail.com" – Sergiy Nov 10 '17 at 18:23
  • Looks like the problem is still there in 27.0.1. I've edited my answer as your suggestion in case someone have the same problem. – Kimi Chiu Nov 17 '17 at 08:17
0

I have found a source code that solved this issue. This issue occur because of AppBarLayout's behavior (AppBarLayout.Behavior). This source code provide an extending or a customizing behavior of behavior of AppBarLayout and set it into the AppBarLayout with introduction of usage both in xml directly or java. I can only explain briefly about it because the source has license that you must read it too. Please see the solution in this link: https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2

Sarith Nob
  • 337
  • 2
  • 13