wake-up-neo.com

Android - Das Element in RecyclerView kann nach dem Scrollen nicht angeklickt werden

Ich habe gerade ein Upgrade auf API 26 durchgeführt und die Bibliothek 26.0.2 unterstützt. Ich habe jedoch festgestellt, dass meine RecyclerView-Elemente nicht direkt nach dem Scrollen anklickbar sind. Wenn Sie eine Sekunde warten, wird es funktionieren. Wenn Sie jedoch sofort auf das Element klicken, wird es nicht angezeigt. Auch wenn RecyclerView überhaupt nicht scrollt (z. B. nach oben scrollen).

Wenn ich zur Unterstützung der Bibliothek 25.4.0 heruntergestuft wurde, ist alles wieder in Ordnung. Der Schlüsselpunkt ist, dass sich meine RecyclerView in einer CoordinatorLayout befindet und auf meiner Toolbar der AppBarLayout ein SCROLL_FLAG_SCROLL-Flag steht. Wenn ich dieses Flag nicht verwende, verschwindet dieses Problem. Ich denke, es ist eine versteckte Verhaltensänderung der Unterstützungsbibliothek 26.

Ich habe versucht, focusable="false" zur CoordinatorLayout hinzuzufügen, hatte aber immer noch kein Glück.

Gibt es eine Möglichkeit, dieses Verhalten zu deaktivieren? Weil es wirklich nervig ist, zweimal zu klicken, um das Klickereignis auszulösen.

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

BEARBEITEN

Ich denke, das Problem ist das scrollState des RecyclerView. Wenn das Scrollen gestoppt ist, wird es nicht sofort in SCROLL_STATE_IDLE geändert. Beim Betrachten des Quellcodes von RecyclerView habe ich festgestellt, dass ViewFlinger den Bildlaufstatus steuert. Wenn ich nach unten rolle, um nach oben zu scrollen, ruft es nicht sofort setScrollState(SCROLL_STATE_IDLE) auf, sondern wartet eine Weile, um diese Methode auszulösen. Je schneller ich fliege, desto mehr Zeit muss ich warten. Es ist genau so, wie der RecyclerView noch im Hintergrund läuft. Weil scroller.isFinished() nicht gleich true zurückkehrt, nachdem RecyclerView das Scrollen beendet hat, wenn es den oberen Bereich berührt. Vielleicht ist es ein Fehler des RecyclerView, wenn es sich in einem CoordinatorLayout befindet.

27
Kimi Chiu

Es wurde ein Weg gefunden, den Scroll-Zustand in den Leerlauf zu zwingen. Warten auf Google, um diesen Fehler zu beheben.

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

BEARBEITEN

Das Problem wurde in der Support-Bibliothek 27.0.1 behoben.

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

Nachdem ein Benutzer einen Bildlauf durchgeführt hat, kann er nicht auf ein Element in einer RecyclerView klicken. (AOSP-Ausgabe 66996774)

Aktualisiert am 17. November 2017

Einige Benutzer berichteten, dass dieses Problem in der Support-Bibliothek 27.0.1 .. nicht behoben wurde .. Der Problem-Tracker befindet sich hier . https://issuetracker.google.com/issues/66996774

Daher können Sie diese offizielle Problemumgehung verwenden https://Gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2

Oder verwenden Sie diese hier.

31
Kimi Chiu

Vielen Dank für diese Frage und Ihre Antwort! Das hat mir viel Zeit gespart. Es tut uns leid, dass Sie dies als Antwort gepostet haben. Ich habe nicht genug Ruf, um einen Kommentar abzugeben.

Ich habe dieses Problem auch bemerkt, aber als neuer Android-Entwickler wusste ich nicht, dass es einen Fehler in der neuen Support-Bibliothek gibt.

Was ich vorschlagen wollte, ist das Hinzufügen dieser Prüfung:

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

Dadurch wird sichergestellt, dass während der Bildlauf durch die RecyclerView keine Elemente angeklickt werden.

Wie ich es verstehe, ist es ein erwartetes Verhalten. Ihre Antwort hat mir jedoch bei dieser Frage geholfen.

4
Sergey

Ich habe einen Quellcode gefunden, der dieses Problem gelöst hat. Dieses Problem tritt aufgrund des Verhaltens von AppBarLayout (AppBarLayout.Behavior) auf. Dieser Quellcode stellt eine Erweiterung oder ein Anpassungsverhalten des Verhaltens von AppBarLayout bereit und legt es in AppBarLayout fest, wobei die Verwendung sowohl in XML direkt als auch in Java eingeführt wird. Ich kann es nur kurz erklären, weil die Quelle eine Lizenz hat, die Sie auch lesen müssen. Die Lösung finden Sie in diesem Link: https://Gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2

0
Sarith NOB