web-dev-qa-db-ja.com

Android-RecyclerView内のアイテムはスクロール後にクリックできません

API 26にアップグレードし、ライブラリ26.0.2をサポートしました。しかし、スクロールした直後にRecyclerViewアイテムをクリックできないことがわかりました。しばらく待つと動作します。ただし、すぐにアイテムをクリックしても、クリックされません。 RecyclerViewがまったくスクロールしていない場合でも(たとえば、一番上までスクロールした場合)。

ライブラリ25.4.0をサポートするためにダウングレードしたとき、すべてが再びうまくいきます。重要な点は、私のRecyclerViewCoordinatorLayoutにあり、ToolbarAppBarLayoutに_SCROLL_FLAG_SCROLL_フラグがあることです。このフラグを使用しないと、この問題はなくなります。だから、サポートライブラリ26の隠された動作の変更だと思います。

_focusable="false"_をCoordinatorLayoutに追加しようとしましたが、まだ運がありませんでした。

この動作を無効にする方法はありますか?クリックイベントをトリガーするために2回クリックするのは本当に面倒だからです。

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

編集

問題はscrollStateRecyclerViewであると思います。スクロールを停止しても、すぐに_SCROLL_STATE_IDLE_に変更されません。 RecyclerViewのソースコードを見ると、スクロール状態を制御するViewFlingerがあることがわかりました。上にスクロールしてスクロールすると、すぐにsetScrollState(SCROLL_STATE_IDLE)が呼び出されず、代わりにこのメソッドがトリガーされるまでしばらく待機します。早く逃げるほど、待つ時間が長くなります。 RecyclerViewがまだバックグラウンドでスクロールしているようです。 scroller.isFinished()は、RecyclerViewが上部に触れたときにスクロールを停止した直後にtrueを返さないためです。 RecyclerViewにあるCoordinatorLayoutのバグかもしれません。

30
Kimi Chiu

スクロール状態を強制的にアイドルにする方法を見つけました。 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'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;
}

編集

この問題は、サポートライブラリ27.0.1で修正されました。

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

ユーザーがスクロールした後、RecyclerViewのアイテムをクリックすることはできません。 (AOSP問題66996774)

2017年11月17日に更新

一部のユーザーは、この問題はサポートライブラリ27.0.1では修正されていないと報告しました。問題追跡ツールはこちらです。 https://issuetracker.google.com/issues/66996774

したがって、この公式の回避策を使用することもできます。 https://Gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2

または、こちらを使用してください。

36
Kimi Chiu

この質問と回答をありがとうございました!それは私に多くの時間を節約しました。これを回答として投稿してすみません。コメントするのに十分な評判がありません。

この問題にも気づきましたが、新しいAndroid開発者として、新しいサポートライブラリ内のバグであることに気付きませんでした。

私が提案したかったのは、このチェックを追加することでもあります:

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

RecyclerViewが実際にスクロールされている間、アイテムをクリックしないようにします。

私が理解しているように、それは予想される動作です。しかし、あなたの答えはこれを助けてくれました question

4
Sergey

この問題を解決するソースコードを見つけました。この問題は、AppBarLayoutの動作(AppBarLayout.Behavior)が原因で発生します。このソースコードは、AppBarLayoutの動作の拡張またはカスタマイズ動作を提供し、xmlまたはJavaの両方での使用を導入してAppBarLayoutに設定します。ソースにはあなたにも読まなければならないライセンスがあるので、私はそれについて簡単に説明するだけです。このリンクの解決策を参照してください: https://Gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2

0
Sarith NOB