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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26580723/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 02:51:53  来源:igfitidea点击:

How to scroll to the bottom of a RecyclerView? scrollToPosition doesn't work

javaandroidscrollandroid-recyclerview

提问by waylaidwanderer

I'd like to scroll to the bottom of the RecyclerView list after loading the activity.

我想在加载活动后滚动到 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(...)throws an exception about being not supported in RecyclerView, and conversationView.scrollToPosition(...)doesn't seem to do anything.

conversationView.scrollTo(...)引发关于 RecyclerView 不支持的异常,并且conversationView.scrollToPosition(...)似乎没有做任何事情。

After the above block of code, I added

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

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

which doesn't work. There are 30 elements in GENERIC_MESSAGE_LIST.

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

采纳答案by yigit

Just set setStackFromEnd=trueor setReverseLayout=trueso that LLM will layout items from end.

只需设置setStackFromEnd=truesetReverseLayout=true使LLM将布局从最终产品。

The difference between these two is that setStackFromEndwill set the view to show the last element, the layout direction will remain the same. (So, in an left-to-right horizontal Recycler View, the last element will be shown and scrolling to the left will show the earlier elements)

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

Whereas setReverseLayoutwill change the order of the elements added by the Adapter. The layout will start from the last element, which will be the left-most in an LTR Recycler View and then, scrolling to the right will show the earlier elements.

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

Sample:

样本:

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

See documentationfor details.

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

回答by ianhanniballake

When you call setAdapter, that does not immediately lay out and position items on the screen (that takes a single layout pass) hence your scrollToPosition()call has no actual elements to scroll to when you call it.

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

Instead, you should register a ViewTreeObserver.OnGlobalLayoutListener(via addOnGlobalLayoutListner()from a ViewTreeObservercreated by conversationView.getViewTreeObserver()) which delays your scrollToPosition()until after the first layout pass:

相反,您应该注册一个ViewTreeObserver.OnGlobalLayoutListener(通过来自created 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.
  }
});

回答by Yuki Yoshida

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

and

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

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

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

above code works, but it's not smooth and not cool.

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

回答by Roc Boronat

I was looking at this post to find the answer but... I think everyone on this post was facing the same scenario as me: scrollToPosition()was fully ignored, for an evident reason.

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

What I was using?

我用的是什么?

recyclerView.scrollToPosition(items.size());

... what WORKED?

...什么工作

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

回答by Muhammad Umair Shafique

To scrolldown from any position in the recyclerview to bottom

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

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

回答by WritingForAnroid

I know its late to answer here, still if anybody want to know solution is below

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

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

回答by Anky An

Only Ian's answer was able to make my RecyclerViewscroll to a specified position. However, The RecyclerViewwas not able to scroll afterwards when I used scrollToPosition(). smoothScrollToPosition()worked but the initial animation made it too slow when the list was long. The reason was the listener was not removed. I used the code below to remove the current ViewTreeObserverand it worked as a charm.

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

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

回答by Wasim Amin

IF you have adapter attached with recyclerView then just do this.

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

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

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

回答by abedfar

Roc answer is a great help. I would like to add a small block to it:

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

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

回答by amaresh hiremani

This works perfectly fine for me:

这对我来说非常好:

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