自动滚动到RecyclerView底部

18
我有一个布局文件中包含 RecyclerView 的碎片。RecyclerView 用于在聊天中显示消息。因此,当打开聊天碎片时,我需要使 RecyclerView 滚动到底部。
我尝试直接滚动 RecyclerView:
var mRecyclerView = view.FindViewById<RecyclerView>
mRecyclerView.ScrollToPosition(mMessages.Count-1);

第二种方法:

LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(Application.Context);
mRecyclerView.SetLayoutManager(mLinearLayoutManager);
mLinearLayoutManager.ScrollToPosition(mMessages.Count - 1);      

第三种方法:

LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(Application.Context);
mRecyclerView.SetLayoutManager(mLinearLayoutManager);
mLinearLayoutManager.ScrollToPositionWithOffset(mMessages.Count - 1, 0);

不幸的是,在任何一种情况下都没有发生任何事情。非常感谢您的建议!

7个回答

23

请使用smoothScrollToPosition来解决您的问题。我总是使用smoothScrollToPosition来重定向到任何位置。

确保mMessages的大小与您想象的一样。

例如,

RecyclerView rv = (RecyclerView)findViewById(R.id.recyclerView);
rv.smoothScrollToPosition(mMessages.count-1);

请确保mMessages的大小与您所想的一样。那是什么意思?SmoothScrollToPosition没有解决我的问题。 - rasperryPi
确保 mMessages 的大小大于屏幕中包含的项目。 - Narendra Sorathiya
你的意思是说这个视图实际上是可滚动的吗?如果是的话,那就是可滚动的。 - rasperryPi

10

很简单,只需更改您的代码为

    RecyclerView recyclerView = findViewById(R.id.recyclerView);
    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setStackFromEnd(true);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(mAdapter);
    recyclerView.smoothScrollToPosition(mAdapter.getItemCount());

如果您在RecyclerView的父布局中使用了ScrollView或NestedScrollView,则它将无法正常工作。因为它仅在RecyclerView没有任何父布局(如ScrollView)时才能正常工作。希望这可以解决您的错误。

9
你可以设置setStackFromEnd=true,这将使视图显示最后一个元素,布局方向保持不变。 编辑后我已更新:就像这样:
   LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(Application.Context);
   mLinearLayoutManager.setStackFromEnd(true); 
   mRecyclerView.SetLayoutManager(mLinearLayoutManager);
   mRecyclerView.scrollToPosition(mMessages.Count-1);

请查看 文档

编辑: 问题在于您调用了 scrollToPosition,但没有为 RecyclerView 设置任何布局管理器。

考虑到 RecyclerView 类中的 scrollToPosition 函数,您的情况是有道理的。

/**
     * Convenience method to scroll to a certain position.
     *
     * RecyclerView does not implement scrolling logic, rather forwards the call to
     * {@link android.support.v7.widget.RecyclerView.LayoutManager#scrollToPosition(int)}
     * @param position Scroll to this adapter position
     * @see android.support.v7.widget.RecyclerView.LayoutManager#scrollToPosition(int)
     */
    public void scrollToPosition(int position) {
        if (mLayoutFrozen) {
            return;
        }
        stopScroll();
        if (mLayout == null) {
            Log.e(TAG, "Cannot scroll to position a LayoutManager set. " +
                    "Call setLayoutManager with a non-null argument.");
            return;
        }
        mLayout.scrollToPosition(position);
        awakenScrollBars();
    }

无法滚动到设置了LayoutManager的位置。请使用非空参数调用setLayoutManager方法。

如果这对你有帮助,请批准我的答案。 - ziLk

3
我找到了问题所在,需要在设置LayoutManager之后再设置RecyclerView的scrollToPosition或smoothScrollToPosition。
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.scrollToPosition(mMessages.count - 1);

希望能对您有所帮助。

@树莓派,请看一下。 - Shamsul

3

我相信你没有正确调用它。除了recycler view,您还需要传递LinearLayoutManager才能使其工作。以下是我是如何使其工作的:

mLayoutManager.smoothScrollToPosition(mRecyclerView, null, array.size() - 1);

也许这与Android在处理Java和Xamarin方面的行为差异有关,但是在Xamarin中,null会导致空对象引用异常。 - rasperryPi

1
  1. 如果你想要直接滚动到最后一项,你可以使用以下代码。

binding.recyclerView.smoothScrollToPosition(adapter.itemCount-1)

如果您想为recyclerview添加连续滚动功能,可以使用这个类。
public class AutoScrollRecyclerView extends RecyclerView {
    private static long delayTime = 45;// How long after the interval to perform scrolling
    AutoPollTask autoPollTask;// Scroll thread
    private boolean running; // Is it rolling?
    private boolean canRun;// Can it be automatically scrolled, depending on whether the data exceeds the screen

    public AutoScrollRecyclerView(Context context) {
        super(context);
    }

    public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        autoPollTask = new AutoPollTask(this);// Instantiate the scroll refresh thread
    }

    static class AutoPollTask implements Runnable {
        private final WeakReference<AutoScrollRecyclerView> mReference;

        // Use weak references to hold external class references to prevent memory leaks
        public AutoPollTask(AutoScrollRecyclerView reference) {
            this.mReference = new WeakReference<>(reference);
        }

        @Override
        public void run() {
            AutoScrollRecyclerView recyclerView = mReference.get();// Get the recyclerview object
            if (recyclerView != null && recyclerView.running && recyclerView.canRun) {
                recyclerView.scrollBy(2, 2);// Note the difference between scrollBy and scrollTo
                //delayed to send
                recyclerView.postDelayed(recyclerView.autoPollTask, delayTime);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                /*if (running)
                    stop();*/
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_OUTSIDE:
                /*if (canRun)
                    start();*/
                break;
        }
        return super.onTouchEvent(e);
    }

    //Open: If it is running, stop first -> then open
    public void start() {
        if (running)
            stop();
        canRun = true;
        running = true;
        postDelayed(autoPollTask, delayTime);
    }
    
    public void stop() {
        running = false;
        removeCallbacks(autoPollTask);
    }
}

0
如果您在recyclerView的父级中使用了ScrollView或NestedScrollView,请尝试以下操作:
parentNestedScrollView.smoothScrollTo(0, parentNestedScrollView.bottom)

有时候这可能不起作用,因为在适配器显示新项目之前尝试更新滚动位置,所以我们需要使用延迟:
 popupView.postDelayed({
        parentNestedScrollView.smoothScrollTo(0, parentNestedScrollView.bottom)
 }, 200)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接