Android - элемент внутри RecyclerView не может быть нажат после прокрутки

Я только что обновил API 26 и поддерживал библиотеку 26.0.2. Но я обнаружил, что мои объекты RecyclerView не могут быть изменены сразу после прокрутки. Если вы подождете секунду, это сработает. Но если вы сразу же щелкнете по элементу, это не произойдет. Даже если RecyclerView не прокручивается вообще (например, прокручивается вверх).

Когда я перешел на поддержку библиотеки 25.4.0, все будет хорошо. Ключевым моментом является то, что мой RecyclerView находится в CoordinatorLayout и имеет флаг SCROLL_FLAG_SCROLL на Toolbar AppBarLayout. Если я не буду использовать этот флаг, эта проблема исчезнет. Поэтому я считаю, что это скрытое изменение поведения библиотеки поддержки.

Я попытался добавить focusable="false" в CoordinatorLayout, но все равно не повезло.

Есть ли способ отключить это поведение? Потому что это очень раздражает щелкнуть дважды, чтобы вызвать событие click.

 <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>

ИЗМЕНИТЬ

Я думаю, что проблема заключается в scrollState RecyclerView. Когда он прекратил прокрутку, он не сразу изменился на SCROLL_STATE_IDLE. Заглянув в исходный код RecyclerView, я нашел там ViewFlinger, управляющий состоянием прокрутки. Когда я перехожу к прокрутке вверх, он не вызывает setScrollState(SCROLL_STATE_IDLE) немедленно, вместо этого он ждет некоторое время, чтобы вызвать этот метод. Чем быстрее я бросаю, тем больше времени мне нужно подождать. Это похоже на то, что RecyclerView все еще прокручивается в фоновом режиме. Поскольку scroller.isFinished() не возвращает true сразу после RecyclerView остановки прокрутки, когда он коснулся вершины. Возможно, это ошибка RecyclerView, когда она находится в CoordinatorLayout.

Ответ 1

Найден способ принудительного прокрутки состояния прокрутки. Ожидание google для исправления этой ошибки.

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

ИЗМЕНИТЬ

Проблема исправлена ​​в библиотеке поддержки 27.0.1.

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

После прокрутки пользователя они не могут нажимать на элемент в RecyclerView. (Вопрос AOSP 66996774)

Обновлено 17 ноября 2017 г.

Некоторые пользователи сообщили, что эта проблема не исправлена ​​в библиотеке поддержки 27.0.1. Трекер проблем находится здесь. https://issuetracker.google.com/issues/66996774

Итак, вы можете использовать это официальное обходное решение. https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2

Или используйте это здесь.

Ответ 2

Большое спасибо за этот вопрос и ваш ответ! Это сэкономило мне много времени. Извините за сообщение об этом в качестве ответа. У меня недостаточно репутации для комментариев.

Я также заметил эту проблему, но, как новый разработчик Android, я не понял, что это ошибка в новой библиотеке поддержки.

То, что я хотел предложить, также добавляет эту проверку:

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

Он будет убедиться, что, хотя RecyclerView фактически прокручивается, мы не нажимаем на какой-либо элемент.

Как я понимаю, это ожидаемое поведение. Однако ваш ответ помог мне с этим question.

Ответ 3

Я нашел исходный код, который решил эту проблему. Эта проблема возникает из-за поведения AppBarLayout (AppBarLayout.Behavior). Этот исходный код обеспечивает расширенное или настраиваемое поведение поведения AppBarLayout и устанавливает его в AppBarLayout с введением использования как в xml напрямую, так и в java. Я могу лишь кратко рассказать об этом, потому что у источника есть лицензия, которую вы тоже должны прочитать. См. Решение по этой ссылке: https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2