web-dev-qa-db-fra.com

Android - l'élément dans RecyclerView ne peut pas être cliqué après le défilement

Je viens de passer à l'API 26 et à la bibliothèque de support 26.0.2. Mais j’ai trouvé que mes éléments RecyclerView ne sont pas cliquables juste après le défilement. Si vous attendez une seconde, cela fonctionnera. Mais si vous cliquez immédiatement sur l'élément, il ne le fera pas. Même si la RecyclerView ne défile pas du tout (par exemple, a fait défiler vers le haut).

Lorsque j'ai rétrogradé pour prendre en charge la bibliothèque 25.4.0, tout va bien à nouveau ... Le point clé est que ma RecyclerView est dans une CoordinatorLayout et a un drapeau SCROLL_FLAG_SCROLL sur ma Toolbar de la AppBarLayout. Si je n'utilise pas ce drapeau, ce problème disparaîtra. Donc, je pense que c'est un changement de comportement caché de la bibliothèque de support 26.

J'ai essayé d'ajouter focusable="false" à la CoordinatorLayout mais je n'ai toujours pas eu de chance.

Est-il possible de désactiver ce comportement? Parce que c'est vraiment ennuyant de cliquer deux fois pour déclencher l'événement 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>

MODIFIER

Je pense que le problème est la scrollState de la RecyclerView. Lorsque le défilement est arrêté, il n'est pas immédiatement remplacé par SCROLL_STATE_IDLE. En regardant dans le code source de RecyclerView, j'ai trouvé qu'il y avait une ViewFlinger contrôlant l'état de défilement. Lorsque je descends pour faire défiler vers le haut, il n'appelle pas setScrollState(SCROLL_STATE_IDLE) immédiatement, il attend un certain temps pour déclencher cette méthode. Plus je lance vite, plus je dois attendre. Tout comme le RecyclerView défile toujours en arrière-plan. Parce que la scroller.isFinished() ne retourne pas vrai juste après la RecyclerView, arrêtez de faire défiler la liste lorsqu'elle touche le haut. Peut-être que c'est un bug de la RecyclerView quand c'est dans une CoordinatorLayout.

27
Kimi Chiu

Nous avons trouvé un moyen de forcer l'état de défilement à être inactif . Nous attendons que Google corrige ce bogue.

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

MODIFIER

Le problème a été corrigé dans la bibliothèque de support 27.0.1.

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

Une fois qu'un utilisateur a fait défiler, il ne peut plus cliquer sur un élément de RecyclerView. (Numéro AOSP 66996774)

Mis à jour le 17 nov. 2017

Certains utilisateurs ont signalé que ce problème n'était pas résolu dans la bibliothèque de support technique 27.0.1 . Le suivi du problème est ici . https://issuetracker.google.com/issues/66996774

Vous pouvez donc utiliser cette solution de contournement officielle . https://Gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2

Ou utilisez celui-ci ici.

31
Kimi Chiu

Merci beaucoup pour cette question et votre réponse! Cela m'a fait gagner beaucoup de temps. Désolé de poster ceci comme une réponse. Je n'ai pas assez de réputation pour commenter.

J'ai également remarqué ce problème, mais en tant que nouveau développeur Android, je n'avais pas réalisé que c'était un bogue dans la nouvelle bibliothèque de support.

Ce que je voulais suggérer, c'est aussi d'ajouter ce chèque:

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

Cela fera en sorte que pendant le défilement de RecyclerView, nous ne cliquons sur aucun élément.

Si je comprends bien, c'est un comportement attendu. Cependant, votre réponse m'a aidé avec cette question .

4
Sergey

J'ai trouvé un code source qui a résolu ce problème. Ce problème est dû au comportement de AppBarLayout (AppBarLayout.Behavior). Ce code source fournit un comportement de comportement d'extension ou de personnalisation d'AppBarLayout et le définit dans AppBarLayout avec l'introduction de l'utilisation à la fois directement en XML ou en Java. Je ne peux expliquer que brièvement parce que la source a une licence qui oblige à la lire aussi. Veuillez voir la solution dans ce lien: https://Gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2

0
Sarith NOB