30 votes

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

Je viens de mettre à l'API 26 et le soutien de la bibliothèque 26.0.2. Mais j'ai trouvé que mes RecyclerView des articles n'est pas cliquable à droite après le défilement. Si vous attendez une seconde, il va fonctionner. Mais si vous cliquez sur l'élément immédiatement, il ne sera pas. Même si l' RecyclerView n'est pas défilement(par exemple a un défilement vers le haut).

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

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

Est-il possible de désactiver ce comportement? Parce que c'est vraiment ennuyeux 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 l' scrollState de la RecyclerView. Quand il est arrêté le défilement, c'est n'est pas modifié ( SCROLL_STATE_IDLE immédiatement. En regardant dans le code source de RecyclerView, j'ai trouvé il y a un ViewFlinger contrôler le défilement de l'état. Quand je la jeter en bas pour faire défiler vers le haut, il n'est pas en appelant setScrollState(SCROLL_STATE_IDLE) immédiatement, au lieu de cela, il attendre un moment pour déclencher cette méthode. Le plus rapide que j'ai fling, le plus de temps je dois attendre. Tout comme la RecyclerView est encore le défilement en arrière-plan. Parce que l' scroller.isFinished() ne retourne pas de véritable droit après l' RecyclerView arrêter le défilement quand il a touché le haut. Peut-être que c'est un bug de l' RecyclerView dans CoordinatorLayout.

42voto

Kimi Chiu Points 1080

Trouvé un moyen de forcer le défilement de l'état inactif. D'attente pour google de corriger ce 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;
}

MODIFIER

Le problème a été corrigé dans la bibliothèque de prise en charge 27.0.1.

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

Après qu'un utilisateur fait défiler, ils ne peuvent pas cliquer sur un élément dans un RecyclerView. (PSBA question 66996774)

Mis à jour le 17 Novembre 2017

Certains utilisateurs ont signalé que ce problème n'est pas résolu dans la bibliothèque de prise en charge 27.0.1. La question tracker est ici. https://issuetracker.google.com/issues/66996774

Vous pouvez ainsi choisir d'utiliser cette officiel de solution de contournement. https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2

Ou l'utiliser ici.

5voto

Sergey Points 76

Merci beaucoup pour cette question et votre réponse! Il m'a sauvé beaucoup de temps. Désolé pour l'affichage de cette comme une réponse. Je n'ai pas assez de réputation pour commentaire.

J'ai aussi remarqué ce problème, mais comme un nouveau développeur Android je ne savais pas que c'est un bug à l'intérieur de la nouvelle bibliothèque de prise en charge.

Ce que je voulais suggérer, c'est aussi l'ajout de cette vérification:

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

Il fera en sorte que tout le RecyclerView est en fait le défilement, nous ne cliquez pas sur n'importe quel élément.

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

0voto

Sarith NOB Points 63

J'ai trouvé un code source qui a résolu ce problème. Ce problème se produit en raison de AppBarLayout du comportement (AppBarLayout.Le comportement). Ce code source de fournir une extension ou une personnalisation du comportement de comportement de AppBarLayout et dans le AppBarLayout avec l'introduction de l'utilisation à la fois en xml directement ou java. Je ne peux l'expliquer brièvement, parce que la source de licence que vous devez lire. Veuillez voir la solution dans ce lien: https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X