180

加载活动后,我想滚动到 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)

这是行不通的。中有 30 个元素GENERIC_MESSAGE_LIST

4

27 回答 27

418

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

我用的是什么?

recyclerView.scrollToPosition(items.size());

...什么工作

recyclerView.scrollToPosition(items.size() - 1);
于 2014-11-21T14:04:42.897 回答
221

只需设置setStackFromEnd=true左右setReverseLayout=true,LLM 将从头开始布局项目。

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

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

样本:

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

有关详细信息,请参阅文档

于 2014-11-21T20:32:44.637 回答
59

我知道在这里回答太晚了,如果有人想知道解决方案如下

conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount() - 1);
于 2016-06-09T07:28:00.233 回答
35

从回收站视图中的任何位置向下滚动到底部

科特林

editText.setOnClickListener {
    rv.postDelayed({                 
        rv.scrollToPosition(rv.adapter.itemCount - 1)
    }, 1000)
}

爪哇

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);
            }
        });
于 2015-11-04T07:33:54.303 回答
17

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

recyclerView.scrollToPosition(mChatList.size() - 1);
于 2018-07-06T11:11:55.540 回答
11

当您调用setAdapter时,它不会立即在屏幕上布局和定位项目(需要一次布局传递),因此您的scrollToPosition()调用在调用时没有实际的元素可以滚动到。

相反,您应该注册一个ViewTreeObserver.OnGlobalLayoutListener(通过create by的addOnGlobalLayoutListner()),它会延迟您直到第一次布局传递之后:ViewTreeObserverconversationView.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.
  }
});
于 2014-10-27T05:54:10.083 回答
7

Kotlin的解决方案:

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

recyclerView.scrollToPosition(recyclerView.adapter.itemCount - 1)
于 2018-10-31T08:13:24.250 回答
6

如果你有适配器与 recyclerView 连接,那么就这样做。

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

于 2017-05-24T13:07:07.323 回答
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));
    }
  }
}

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

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

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

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

于 2014-10-28T13:45:49.297 回答
5

在科特林:

recyclerView.viewTreeObserver.addOnGlobalLayoutListener { scrollToEnd() }

private fun scrollToEnd() =
        (adapter.itemCount - 1).takeIf { it > 0 }?.let(recyclerView::smoothScrollToPosition)
于 2018-02-04T23:28:24.610 回答
4

在我的视图没有相同高度的情况下,在 LayoutManager 上调用 scrollToPosition可以真正滚动到底部并完全看到最后一项:

recycler.getLayoutManager().scrollToPosition(adapter.getItemCount() - 1);
于 2018-01-31T13:01:23.280 回答
4

大鹏的回答很有帮助。我想给它添加一个小块:

mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);
于 2017-06-26T20:10:40.053 回答
4

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

binding.recyclerView.scrollToPosition(adapter.getItemCount() - 1);
于 2021-03-14T00:14:19.177 回答
4

答案是

recyclerView.scrollToPosition(arrayList.size() - 1);

每个人都提到过。

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

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

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

我的实际代码是:

//scroll to bottom after sending message.
binding.chatRecyclerView.scrollToPosition(messageArrayList.size() - 1);
于 2021-01-06T19:01:51.830 回答
3

第一次进入回收站视图时第一次滚动然后使用

linearLayoutManager.scrollToPositionWithOffset(messageHashMap.size()-1

为向下滚动放入负数为向上滚动放入正值);

如果视图的高度非常大,那么 scrolltoposition 特定的偏移量用于视图的顶部,那么您使用

int overallXScroldl =chatMessageBinding.rvChat.computeVerticalScrollOffset();
chatMessageBinding.rvChat.smoothScrollBy(0, Math.abs(overallXScroldl));
于 2019-06-05T17:12:31.820 回答
2

这对我来说非常好:

AdapterChart adapterChart = new AdapterChart(getContext(),messageList);
recyclerView.setAdapter(adapterChart);
recyclerView.scrollToPosition(recyclerView.getAdapter().getItemCount()-1);
于 2017-07-19T14:47:09.753 回答
1

可以滚动到最后一项的底部,如果最后一项的高度太大,需要偏移

 private void scrollToBottom(final RecyclerView recyclerView) {
        // scroll to last item to get the view of last item
        final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        final RecyclerView.Adapter adapter = recyclerView.getAdapter();
        final int lastItemPosition = adapter.getItemCount() - 1;
    
        layoutManager.scrollToPositionWithOffset(lastItemPosition, 0);
        recyclerView.post(new Runnable() {
            @Override
            public void run() {
                // then scroll to specific offset
                View target = layoutManager.findViewByPosition(lastItemPosition);
                if (target != null) {
                    int offset = recyclerView.getMeasuredHeight() - target.getMeasuredHeight();
                    layoutManager.scrollToPositionWithOffset(lastItemPosition, offset);
                }
            }
        });



    }
于 2021-02-01T10:00:51.273 回答
1

此代码将首先为您提供最新帖子,我认为此答案很有帮助。

    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);
于 2018-04-11T03:01:24.433 回答
1

如果你在使用他,你必须AppBarLayout先隐藏起来scrollToPosition

于 2020-09-22T19:38:13.587 回答
1

尝试了@galex的一种方法,它一直工作到重构。因此,我使用了@yanchenko的答案并进行了一些更改。可能这是因为我调用了 scrolling from 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)
            }
        }
    })
}

您还可以viewTreeObserver.isAlivehttps://stackoverflow.com/a/39001731/2914140中添加类似的检查。

于 2019-05-22T16:54:26.843 回答
1

我知道这为时已晚,但这对我有用,所以我正在回答这个问题

第一的,

LinearLayoutManager layoutManager=new LinearLayoutManager(this);
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager);

在那之后,

database.addValueEventListener(....){
@override
public void onDataCange(...){
....
....
//put this line here
recyclerView.smoothScrollToPosition(recyclerView.getAdapter().getItemCount()-1);
}
}
于 2021-07-09T16:06:51.313 回答
0

如果这些都不起作用,

你应该尝试使用:

ConstraintLayout targetView = (ConstraintLayout) recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount()-1).itemView;
targetView.getParent().requestChildFocus(targetView, targetView);

通过这样做,您请求显示某个 ConstraintLayout(或任何您拥有的)。卷轴是即时的。

我什至在显示键盘的情况下也能工作。

于 2020-06-22T00:55:17.357 回答
0

只有伊恩的回答能够让我RecyclerView滚动到指定的位置。但是,RecyclerView当我使用scrollToPosition(). smoothScrollToPosition()有效,但是当列表很长时,初始动画使它变得太慢。原因是监听器没有被移除。我使用下面的代码来删除电流ViewTreeObserver,它起到了一种魅力。

    mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mRecyclerView.scrollToPosition(mPosition);
            mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });
于 2017-04-21T11:48:49.227 回答
0

如果你使用 kotlin,试试这个

conversationView.post {
    scrollToPosition(conversationView?.adapter.itemCount - 1)
}
于 2021-12-02T02:21:07.173 回答
0

如果您只想从最终用途开始:

layoutManager.stackFromEnd = true

(科特林解决方案)

于 2021-02-12T21:59:33.663 回答
0

如果您使用 reversedLayout “聊天界面”,特别是如果您有图像,您可以尝试以下操作:

首先,向适配器注册DataObserver

   chatAdapter.registerAdapterDataObserver(object : 
                         RecyclerView.AdapterDataObserver() {

   override fun onItemRangeInserted(positionStart: Int itemCount: Int) {

      val messageCount: Int = chatAdapter.itemCount

      val lastVisiblePosition: Int =
            layoutManager.findLastCompletelyVisibleItemPosition()

         if (lastVisiblePosition == -1 || positionStart <= (messageCount - 1)) {
            recyclerView.scrollToPosition(positionStart)
        }
    }
}) 

一旦您为适配器设置数据,这将被调用

其次,您必须像这样向 recyclerView 添加一个滚动侦听器:

   recyclerView.addOnScrollListener(object 
     :RecyclerView.OnScrollListener() {

       override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: 
          Int) {
            super.onScrolled(recyclerView, dx, dy)

          val lastVisiblePosition: Int =
              layoutManager.findLastCompletelyVisibleItemPosition()
        if (lastVisiblePosition != -1 && lastVisiblePosition < 
                chatAdapter.itemCount - 1) {
            recyclerView.smoothScrollToPosition(0)
        }
    }
})
于 2022-02-21T15:44:15.393 回答
-4

仅使用重力即可轻松解决

机器人:layout_gravity="底部"

于 2021-07-22T11:42:07.453 回答