web-dev-qa-db-ja.com

RecyclerViewで可視アイテムを取得する

RecyclerViewにどの要素が現在表示されているかを知る必要があります。 ListViewsの OnScrollListener.onScroll(...) メソッドに相当するものはありません。私は View.getGlobalVisibleRect(...) で作業しようとしましたが、そのハックは醜すぎていつもうまくいくとは限らない。

誰かアイデアがありますか?

229
rekire

最初/最後に見える子はLayoutManagerに依存します。 LinearLayoutManagerまたはGridLayoutManagerを使用している場合は、次のように使用できます。

int findFirstVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition();
int findLastVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();

例えば:

GridLayoutManager layoutManager = ((GridLayoutManager)mRecyclerView.getLayoutManager());
int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();

LinearLayoutManagerの場合、first/lastはアダプタの順序によって異なります。 RecyclerViewから子供たちに問い合わせてはいけません。 LayoutManagerはキャッシングのために見えるよりも多くの項目をレイアウトすることを好むかもしれません。

513
yigit

最後に、アダプタのonBindViewHolderイベントから、現在の項目が表示されているかどうかを確認するための解決策を見つけました。

重要なのは、LayoutManagerのメソッドisViewPartiallyVisibleです。

アダプタでは、RecyclerViewからLayoutManagerを取得できます。これは、 onAttachedToRecyclerView イベントのパラメータとして取得します。

7
Ernesto Vega

表示可能な各子を取得するにはrecyclerView.getChildAt()を使用できます。アダプタコードでこれらのビューにタグconvertview.setTag(index)を設定すると、アダプタデータと関連付けるのに役立ちます。

4

StaggeredGridLayoutManagerの場合、これを行います。

RecyclerView rv = findViewById(...);
StaggeredGridLayoutManager lm = new StaggeredGridLayoutManager(...);
rv.setLayoutManager(lm);

そして目に見えるアイテムビューを得るために:

int[] viewsIds = lm.findFirstCompletelyVisibleItemPositions(null);
ViewHolder firstViewHolder = rvPlantios.findViewHolderForLayoutPosition(viewsIds[0]);
View itemView = viewHolder.itemView;

空かどうかを確認してください。

以下のLinear / Grid LayoutManagerメソッドはどのアイテムがvisibleであるかをチェックするために使用することができます

int findFirstVisibleItemPosition();
int findLastVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();

もしあなたが何らかのしきい値でis item visible on screenを追跡したいのなら、あなたは以下のブログを参照することができます。

https://proandroiddev.com/detecting-list-items-perceived-by-user-8f164dfb1d05

0
Sumit Jain

補遺

提案された関数 findLast ... Position() do not は、ツールバーが展開されているときに折りたたみ式ツールバーがあるシナリオでは正しく機能します。

リサイクラビューの高さは固定されているようで、ツールバーが展開されている間は、リサイクラが下に移動し、画面の一部が見えなくなります。結果として、提案された機能の結果は高すぎる。例:最後の目に見えるアイテムは#9であると言われます、しかし実際にはアイテム#7はスクリーン上にある最後のアイテムです。

この動作が、ビューが正しい位置にスクロールできなかった、つまりscrollToPosition()が正しく機能しなかった(プログラムによってツールバーを最後に折りたたんだ)理由でもあります。

0

recyclerViewアダプタの内部に実装するロジックを持っている人のために、RecyclerViewが調べられるのでwhat you wantを取得するためにon scrollListenerと組み合わせて@ernestoアプローチをまだ使うことができます。アダプタの中には、次のようなものがあります。

@Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if(manager instanceof LinearLayoutManager && getItemCount() > 0) {
            LinearLayoutManager llm = (LinearLayoutManager) manager;
            recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                }

                @Override
                public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                        int visiblePosition = llm.findFirstCompletelyVisibleItemPosition();
                        if(visiblePosition > -1) {
                            View v = llm.findViewByPosition(visiblePosition);
                            //do something
                            v.setBackgroundColor(Color.parseColor("#777777"));
                        }
                }
            });
        }
    }
0
Aleyam