web-dev-qa-db-ja.com

RecyclerViewの一番下までスクロールするにはどうすればいいですか? scrollToPositionが機能しません

アクティビティを読み込んだ後、RecyclerViewリストの一番下までスクロールしたいです。

GENERIC_MESSAGE_LIST = (ArrayList) intent.getExtras().getParcelableArrayList(ConversationsAdapter.EXTRA_MESSAGE);
conversationView = (RecyclerView) findViewById(R.id.list_messages);
conversationView.setHasFixedSize(true);
conversationViewLayoutManager = new LinearLayoutManager(this);
conversationView.setLayoutManager(conversationViewLayoutManager);
conversationViewAdapter = new ConversationAdapter(GENERIC_MESSAGE_LIST, this);
conversationView.setAdapter(conversationViewAdapter);

conversationView.scrollTo(...)はRecyclerViewでサポートされていないという例外を投げ、そしてconversationView.scrollToPosition(...)は何もしないようです。

上記のコードブロックの後に、私は追加しました

conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size() + 1)

これはうまくいきません。 GENERIC_MESSAGE_LISTには30個の要素があります。

130
waylaidwanderer

LLMが項目を最後からレイアウトするようにsetStackFromEnd=trueまたはsetReverseLayout=trueを設定するだけです。

これら2つの違いは、setStackFromEndはビューに最後の要素を表示するように設定し、レイアウトの方向は同じままであるということです。 (したがって、左から右への横方向のリサイクルビューでは、最後の要素が表示され、左にスクロールすると前の要素が表示されます)

setReverseLayoutは、アダプタによって追加された要素の順序を変更します。レイアウトは最後の要素から開始します。最後の要素はLTRリサイクルビューで一番左に表示され、次に右にスクロールすると前の要素が表示されます。

サンプル:

final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setReverseLayout(true);
_listView.setLayoutManager(linearLayoutManager);

詳しくは documentation を参照してください。

175
yigit

答えを見つけるためにこの記事を見ていましたが...私はこの記事のすべての人が私と同じシナリオに直面していたと思います。明らかな理由でscrollToPosition()は完全に無視されました。

私が使っていたもの

recyclerView.scrollToPosition(items.size());

...何_

recyclerView.scrollToPosition(items.size() - 1);
318
Roc Boronat

誰かが解決策を知りたいのであれば、私はここで答えるのが遅れているのを知っています

conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount() - 1);
44

Recyclerviewの任意の位置から下にスクロールするには

edittext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                rv_commentList.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                      rv_commentList.scrollToPosition(rv_commentList.getAdapter().getItemCount() - 1);
                    }
                }, 1000);
            }
        });

setAdaptername__を呼び出しても、すぐにはレイアウトされず、画面上に項目が配置されません(1回のレイアウトパスが必要です)。したがって、scrollToPosition()呼び出しには、呼び出すときにスクロールする実際の要素はありません。

代わりに、 ViewTreeObserver.OnGlobalLayoutListener を登録する必要があります( addOnGlobalLayoutListner() を使用)。最初のレイアウトパスが終わるまでconversationView.getViewTreeObserver()を遅らせるscrollToPosition())によって作成されたViewTreeObservername__から:

conversationView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
  public void onGlobalLayout() {
    conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size();
    // Unregister the listener to only call scrollToPosition once
    conversationView.getViewTreeObserver().removeGlobalOnLayoutListener(this);

    // Use vto.removeOnGlobalLayoutListener(this) on API16+ devices as 
    // removeGlobalOnLayoutListener is deprecated.
    // They do the same thing, just a rename so your choice.
  }
});
9
ianhanniballake

メッセージを送信した後、サーバーからメッセージを取得する前にこのコードを追加します。

recyclerView.scrollToPosition(mChatList.size() - 1);
9
Shubham Agrawal
class MyLayoutManager extends LinearLayoutManager {

  public MyLayoutManager(Context context) {
    super(context, LinearLayoutManager.VERTICAL, false);
  }

  @Override public void smoothScrollToPosition(RecyclerView recyclerView,
      final RecyclerView.State state, final int position) {

    int fcvip = findFirstCompletelyVisibleItemPosition();
    int lcvip = findLastCompletelyVisibleItemPosition();

    if (position < fcvip || lcvip < position) {
      // scrolling to invisible position

      float fcviY = findViewByPosition(fcvip).getY();
      float lcviY = findViewByPosition(lcvip).getY();

      recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {

        int currentState = RecyclerView.SCROLL_STATE_IDLE;

        @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

          if (currentState == RecyclerView.SCROLL_STATE_SETTLING
              && newState == RecyclerView.SCROLL_STATE_IDLE) {

            // recursive scrolling
            smoothScrollToPosition(recyclerView, state, position);
          }

          currentState = newState;
        }

        @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

          int fcvip = findFirstCompletelyVisibleItemPosition();
          int lcvip = findLastCompletelyVisibleItemPosition();

          if ((dy < 0 && fcvip == position) || (dy > 0 && lcvip == position)) {
            // stop scrolling
            recyclerView.setOnScrollListener(null);
          }
        }
      });

      if (position < fcvip) {
        // scroll up

        recyclerView.smoothScrollBy(0, (int) (fcviY - lcviY));
      } else {
        // scroll down

        recyclerView.smoothScrollBy(0, (int) (lcviY - fcviY));
      }
    } else {
      // scrolling to visible position

      float fromY = findViewByPosition(fcvip).getY();
      float targetY = findViewByPosition(position).getY();

      recyclerView.smoothScrollBy(0, (int) (targetY - fromY));
    }
  }
}

そして

MyLayoutManager layoutManager = new MyLayoutManager(context);
recyclerView.setLayoutManager(layoutManager);

RecyclerView.Adapter adapter = new YourAdapter();
recyclerView.setAdapter(adapter);

recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1);

上記のコードは機能しますが、スムーズではなくクールではありません。

4
Yuki Yoshida

RecyclerViewでアダプタを接続している場合は、これを実行してください。

mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount());

4
Wasim Amin

ビューの高さが同じではない私の場合は、LayoutManagerで scrollToPosition を呼び出すと、実際には下にスクロールして最後の項目を完全に見てください。

recycler.getLayoutManager().scrollToPosition(adapter.getItemCount() - 1);
4
galex

Kotlinの解決策:

"recyclerView.adapter"の設定後または "recyclerView.adapter.notifyDataSetChanged()"の後に、コードの下に適用

recyclerView.scrollToPosition(recyclerView.adapter.itemCount - 1)
4
chinnuabhi

Roc answerは大いに役立ちます。小さなブロックを追加したいと思います。

mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);
3
abedfar

これは私にとっては完全にうまくいきます:

AdapterChart adapterChart = new AdapterChart(getContext(),messageList);
recyclerView.setAdapter(adapterChart);
recyclerView.scrollToPosition(recyclerView.getAdapter().getItemCount()-1);
2

コトリンでは:

recyclerView.viewTreeObserver.addOnGlobalLayoutListener { scrollToEnd() }

private fun scrollToEnd() =
        (adapter.itemCount - 1).takeIf { it > 0 }?.let(recyclerView::smoothScrollToPosition)
2
yanchenko

@ galex の方法を試してみましたが、リファクタリングまではうまくいきました。そこで、私は @ yanchenko の答えを使い、少し変更しました。おそらくこれは、フラグメントビューが構築された(そしておそらく正しいサイズではなかった)onCreateView()からスクロールを呼び出したためです。

private fun scrollPhotosToEnd(view: View) {
    view.recycler_view.viewTreeObserver.addOnGlobalLayoutListener(object :
        ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                view.recycler_view.viewTreeObserver.removeOnGlobalLayoutListener(this)
            } else {
                @Suppress("DEPRECATION")
                view.recycler_view.viewTreeObserver.removeGlobalOnLayoutListener(this)
            }
            adapter?.itemCount?.takeIf { it > 0 }?.let {
                view.recycler_view.scrollToPosition(it - 1)
            }
        }
    })
}

https://stackoverflow.com/a/39001731/291414 のようにviewTreeObserver.isAliveのチェックを追加することもできます。

0
CoolMind

このコードは最初にあなたに最新の投稿をするでしょう、私はこの答えが役に立つと思います。

    mInstaList=(RecyclerView)findViewById(R.id.insta_list);
    mInstaList.setHasFixedSize(true);

    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

    mInstaList.setLayoutManager(layoutManager);
    layoutManager.setStackFromEnd(true);
    layoutManager.setReverseLayout(true);
0
hasanga lakdinu

私のRecyclerViewを指定された位置にスクロールさせることができたのは、Ianの答えだけでした。しかし、私がscrollToPosition()を使用したとき、RecyclerViewはその後スクロールできませんでした。 smoothScrollToPosition()は動作しましたが、最初のアニメーションではリストが長いときは遅すぎました。その理由はリスナーが削除されなかったことです。私は現在のViewTreeObserverを削除するために以下のコードを使用しました、そしてそれは魅力として働きました。

    mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mRecyclerView.scrollToPosition(mPosition);
            mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });
0
Anky An

初めてリサイクラービューに入るときにはじめてスクロールしてからlinearLayoutManager.scrollToPositionWithOffset(messageHashMap.size() - 1、上にスクロールするにはマイナスに、正の値に入れる)を使用します);を使用します。

ビューの高さが非常に大きい場合は、scrolltopositionの特定のオフセットがビューの上部に使用されます。

int overallXScroldl = chatMessageBinding.rvChat.computeVerticalScrollOffset();chatMessageBinding.rvChat.smoothScrollBy(0、Math.abs(overallXScroldl));

0
Dishant Kawatra