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
.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With