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

时间:2014-10-27 03:17:10

标签: 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);

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

在上面的代码块之后,我添加了

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

哪个不起作用。 GENERIC_MESSAGE_LIST中有30个元素。

25 个答案:

答案 0 :(得分:312)

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

我在用什么?

recyclerView.scrollToPosition(items.size());

......什么工作

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

答案 1 :(得分:174)

只需设置 setStackFromEnd=true setReverseLayout=true ,以便LLM从最后布置项目。

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

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

样品:

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

有关详细信息,请参阅documentation

答案 2 :(得分:44)

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

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

答案 3 :(得分:11)

从recyclelerview中的任何位置向下滚动

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

答案 4 :(得分:9)

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

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

答案 5 :(得分:9)

当你拨打setAdapter时,它不会立即布局并在屏幕上定位项目(只需一次布局),因此你的scrollToPosition()来电没有实际的元素可以在你打电话时滚动到它

相反,您应该注册一个ViewTreeObserver.OnGlobalLayoutListener(通过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. } }); ,这会延迟您的{{1}},直到第一次布局过后:

{{1}}

答案 6 :(得分:4)

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);

以上代码有效,但它并不流畅而且不酷。

答案 7 :(得分:4)

如果您使用recyclerView连接了适配器,那么就这样做。

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

答案 8 :(得分:4)

科特林的解决方案:

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

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

答案 9 :(得分:4)

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

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

答案 10 :(得分:3)

罗克回答是一个很大的帮助。我想在其中添加一个小块:

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

答案 11 :(得分:2)

答案是

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

每个人都提到过。

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

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

注意:这段代码是用 Java 编写的。

我的实际代码是:

//scroll to bottom after sending message.
binding.chatRecyclerView.scrollToPosition(messageArrayList.size() - 1);

答案 12 :(得分:2)

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

binding.recyclerView.scrollToPosition(adapter.getItemCount() - 1);

答案 13 :(得分:2)

在Kotlin:

recyclerView.viewTreeObserver.addOnGlobalLayoutListener { scrollToEnd() }

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

答案 14 :(得分:2)

这对我来说非常好:

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

答案 15 :(得分: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);
                }
            }
        });



    }

答案 16 :(得分:0)

我知道这太晚了,但这对我有用,所以我正在回答这个问题

首先,

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

答案 17 :(得分:0)

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

layoutManager.stackFromEnd = true

(Kotlin 解决方案)

答案 18 :(得分:0)

这段代码会先给你发新帖,我觉得这个答案很有帮助。

    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);

答案 19 :(得分:0)

如果您正在使用AppBarLayout,则必须在scrollToPosition之前将其隐藏

答案 20 :(得分:0)

如果这些都不起作用,

您应该尝试使用:

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

通过执行此操作,您正在请求显示某些ConstraintLayout(或任何其他内容)。滚动是即时的。

即使在显示键盘的情况下,我也可以工作。

答案 21 :(得分:0)

首次进入回收者视图时进行第一次滚动,然后使用        linearLayoutManager.scrollToPositionWithOffset(messageHashMap.size()-1,减去负号即可向下滚动,向上滚动则为正值)

如果视图高度很大,则使用scrolltoposition特定偏移量作为视图顶部,然后使用

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

答案 22 :(得分:0)

尝试了@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/2914140中一样添加viewTreeObserver.isAlive的支票。

答案 23 :(得分:0)

只有伊恩的答案才能让我的RecyclerView滚动到指定的位置。但是,当我使用RecyclerView时,scrollToPosition()无法滚动。 smoothScrollToPosition()有效,但是当列表很长时,初始动画会使它太慢。 原因是听众没有被删除。我使用下面的代码删除了当前的ViewTreeObserver,它可以作为一个魅力。

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

答案 24 :(得分:-1)

仅使用重力来轻松解决

android:layout_gravity="bottom"