如何滚动到RecyclerView的底部?scrollToPosition不起作用

way*_*rer 144 java android scroll android-recyclerview

我想在加载活动后滚动到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);
Run Code Online (Sandbox Code Playgroud)

conversationView.scrollTo(...)抛出了一个关于在RecyclerView中不受支持的例外,并且conversationView.scrollToPosition(...)似乎没有做任何事情.

在上面的代码块之后,我补充道

conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size() + 1)
Run Code Online (Sandbox Code Playgroud)

这不起作用.有30个元素GENERIC_MESSAGE_LIST.

Roc*_*nat 344

我正在看这篇文章找到答案但是......我认为这篇文章中的每个人都面临着与我相同的情景:scrollToPosition()完全被忽略,原因很明显.

我在用什么?

recyclerView.scrollToPosition(items.size());
Run Code Online (Sandbox Code Playgroud)

......什么保护正常工作

recyclerView.scrollToPosition(items.size() - 1);
Run Code Online (Sandbox Code Playgroud)

  • 这对我有用.它实际上是有道理的,因为Java列表是基于零的.例如,列表[0,1,2]的大小为3,但最后一个位置为2,因为它从0开始. (22认同)
  • 仅供参考,对于平滑滚动,有"smoothScrollToPosition(...)". (17认同)
  • `recyclerView.scrollToPosition(messages.size() - 1);`真的对我有用,我只是想知道原因. (4认同)
  • @Ivan Morgilo smoothScrollToPosition根本不起作用:S (4认同)
  • @IvanMorgillo - 你的答案看起来效果更好,结果想要更平滑= D. 看起来像滚动到位置对我来说有点儿麻烦(我的猜测是在调用的函数和视图的创建之间有一个小的延迟?反正它没有正常工作) (2认同)

yig*_*git 182

只需设置setStackFromEnd=truesetReverseLayout=true以便LLM将从最后布局项目.

这两者之间的区别在于setStackFromEnd将视图设置为显示最后一个元素,布局方向将保持不变.(因此,在从左到右的水平Recycler View中,将显示最后一个元素,向左滚动将显示较早的元素)

setReverseLayout将更改适配器添加的元素的顺序.布局将从最后一个元素开始,该元素将在LTR Recycler View中最左侧,然后向右滚动将显示较早的元素.

样品:

final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setReverseLayout(true);
_listView.setLayoutManager(linearLayoutManager);
Run Code Online (Sandbox Code Playgroud)

请参阅文档了解详细信

  • 这可能是有用的,但它似乎没有回答所提出的问题. (114认同)
  • 对于聊天视图,linearLayoutManager.setStackFromEnd(true)有效. (9认同)
  • 这根本不能解决这个问题. (6认同)
  • recyclerView.setStackFromEnd(true)为我工作 (4认同)
  • 如果同时设置stackFromEnd = true和setReverseLayout = true,则它不起作用.有谁知道任何解决方法? (4认同)
  • 仅在视图已满之前有效。它不打算滚动,只是从底部堆叠。 (3认同)

小智 49

我知道最近在这里回答,如果有人想知道解决方案如下

conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount() - 1);
Run Code Online (Sandbox Code Playgroud)

  • 它应该是`conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount()** - 1**);`因为列表中的位置是从零开始的. (7认同)
  • 如果最后一行的高度超过屏幕高度,这将无济于事. (2认同)

Muh*_*que 14

从Recyclerview中的任何位置向下滚动到底部

edittext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                rv.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                      rv.scrollToPosition(rv.getAdapter().getItemCount() - 1);
                    }
                }, 1000);
            }
        });
Run Code Online (Sandbox Code Playgroud)


Shu*_*wal 14

发送消息后和从服务器获取消息之前添加此代码

recyclerView.scrollToPosition(mChatList.size() - 1);
Run Code Online (Sandbox Code Playgroud)


ian*_*ake 9

当你打电话setAdapter时,它没有立即布局并在屏幕上定位项目(只需要一个布局通过),因此你scrollToPosition()调用它时没有实际的元素可以滚动到它.

相反,你应该注册一个ViewTreeObserver.OnGlobalLayoutListener(通过addOnGlobalLayoutListner()ViewTreeObserver被创造conversationView.getViewTreeObserver()),它的延迟scrollToPosition(),直到第一个布局后传:

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.
  }
});
Run Code Online (Sandbox Code Playgroud)


Bad*_*del 8

答案是

recyclerView.scrollToPosition(arrayList.size() - 1);
Run Code Online (Sandbox Code Playgroud)

大家都提到过。

但我面临的 问题是它没有正确放置

我尝试并放置在之后adapter.notifyDataSetChanged();并且它起作用了。每当回收器视图中的数据发生变化时,它会自动滚动到底部,就像发送消息或您第一次打开聊天列表后一样。

注意:此代码是用 Java 测试的。

对我来说实际的代码是:

//scroll to bottom after sending message.
binding.chatRecyclerView.scrollToPosition(messageArrayList.size() - 1);
Run Code Online (Sandbox Code Playgroud)


小智 6

如果您的适配器与 recyclerView 相连,则只需执行此操作。

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


Abh*_*yMe 6

Kotlin解决方案:

在设置“ recyclerView.adapter”之后或在“ recyclerView.adapter.notifyDataSetChanged()”之后应用以下代码

recyclerView.scrollToPosition(recyclerView.adapter.itemCount - 1)
Run Code Online (Sandbox Code Playgroud)


小智 6

如果您在使 recyclerview 滚动到最新内容时遇到问题,请检查 recyclerview 是否不在nestedScrollView 内。那是我的问题。我必须删除nestedScrollview,然后下面的代码才能工作。

binding.recyclerView.scrollToPosition(adapter.getItemCount() - 1);
Run Code Online (Sandbox Code Playgroud)


Yuk*_*ida 5

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));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1);
Run Code Online (Sandbox Code Playgroud)

上面的代码有效,但不流畅也不酷。


abe*_*far 5

Roc 的回答很有帮助。我想在其中添加一个小块:

mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);
Run Code Online (Sandbox Code Playgroud)


yan*_*nko 5

在科特林:

recyclerView.viewTreeObserver.addOnGlobalLayoutListener { scrollToEnd() }

private fun scrollToEnd() =
        (adapter.itemCount - 1).takeIf { it > 0 }?.let(recyclerView::smoothScrollToPosition)
Run Code Online (Sandbox Code Playgroud)