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


回答:


579

最初/最後に表示される子はに依存しますLayoutManagerLinearLayoutManagerまたはを使用している場合はGridLayoutManager

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

例えば:

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

の場合LinearLayoutManager、最初/最後はアダプターの注文によって異なります。から子を照会しないでくださいRecyclerViewLayoutManagerキャッシュ用に表示されるよりも多くのアイテムをレイアウトすることを好むかもしれません。


10
LayoutManagerへの参照を渡さずにRecyclerView.Adapterからこのメソッドにアクセスする可能性はありますか?
Yorgi

3
@Yorgiのように-アダプターの内部は便利なようです。onBindViewHolderを使用して、ユーザーがスクロールしているときに実際に画面に表示されているパターンを追跡するために開発できるパターンがあるのでしょうか。
RoundSparrow hilltx 2015

7
getItemCountfindFirstVisibleItemPosition同じ呼び出しで1と-1を返すことができます。
mbmc 2015

4
StaggeredLayoutManagerについて何を提案できますか?
hornet2319

37
これらの方法は信頼性が非常に低いため、まったく役に立ちません。特にnotifyDataSetChanged / itemRemoved / RangeChangedの後
JK

12

最後に、アダプターのonBindViewHolderイベントから、現在のアイテムが表示されているかどうかを確認するソリューションを見つけました。

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

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


しかし、レイアウトマネージャーがnullではないこのメソッドをどこで呼び出しますか?
6rchid

アダプターのonAttachedToRecyclerViewイベントを待つ必要があります。そのイベントでは、RecyclerViewをパラメーターとして受け取ります。その後、RecyclerVieからLayoutManagerを取得し、それをグローバル変数に保存できます。LayoutManagerがnullの場合、おそらくそれがActivity / Fragment / LayoutのRecyclerViewに割り当てられていなかったことが原因である可能性があります。そして、その割り当ての後にアダプターを構築してみてください。
Ernesto Vega

ソースコードによると、isViewPartiallyVisibleはひどく壊れています。fullyVisibleがtrueの場合、ビューが完全に表示されていればtrueを返します。ただし、falseの場合、ビューが部分的に表示されているか表示されていない場合にtrueを返す結果を単に否定します。ドキュメントでさえ意味がありません。
Molanda


9

RecyclerViewアダプター内に実装されるロジックを持っている人は、@ ernestoアプローチをon scrollListenerと組み合わせて使用​​しwhat you wantて、RecyclerViewが参照されるときに取得できます。アダプター内には、次のようなものが含まれます。

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

7

を使用recyclerView.getChildAt()して、表示されている各子を取得できます。convertview.setTag(index)アダプタコードでこれらのビューにタグを設定すると、アダプタデータと関連付けることができます。


getChildAt()の問題は、要素の順序が5つの要素(0、5、4、3、2、1)から外れる可能性があることです(子の数は、主に> =表示される項目の数です)。したがって、getGlobalVisibleRectを使用して要素の順序を取得しようとしました。
14

あなたの実際の要件は何ですか、実際の順序で可視の子(画面内の子)を取得しますか?
Sreejith B Naick 14

今、私はどの要素が中央にあるのか知りたいのですが、後で境界にも興味があるかもしれません。
2014

1
あなただけから見えるアイテムを取得するrecyclerView.getChildAt()、thatsのは、どのように一般的にRecyclerView動作します。RecyclerView現在表示されているいくつかの子ビューのみを保持しようとし(つまり、画面の境界内で、Visibility as GONE、INVISIBLEではありません)、ユーザーがスクロールしたときにこれらのビューをリサイクルしようとします。
Sreejith B Naick 2015

6
visibleChild = recyclerView.getChildAt(0);を表示します。int positionOfChild = recyclerView.getChildAdapterPosition(visibleChild);
Kevin Lee

5

補遺

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

リサイクラービューの高さが固定されているようです。ツールバーが展開されている間、リサイクラーは下に移動し、画面の一部から外れます。結果として、提案された関数の結果は高すぎます。例:最後に表示されるアイテムは#9と表示されますが、実際にはアイテム#7が画面に表示される最後のアイテムです。

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


それは事実ですが、これは折りたたみツールバーが機能する方法です。1年前にAndroidアプリの開発をやめましたが、そのことは覚えています。
rekire


3

以下の場合は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;

空であることを確認してください。


「空かどうかを確認」とはどういう意味ですか?どのように確認しますか?
tmm1 2018年

viewsIdsは配列であり、空の場合があります。
ダグラスナシフローマジュニア2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.