RecyclerView - 滚动到每次都不起作用的位置

Abb*_*bas 26 android android-recyclerview linearlayoutmanager

我已经实现了水平滚动RecyclerView.我RecyclerView使用了LinearLayoutManager,而我面临的问题是,当我尝试使用scrollToPosition(position)smoothScrollToPosition(position)LinearLayoutManagerscrollToPositionWithOffset(position).对我来说都不适用.滚动调用不会滚动到所需位置,也不会调用OnScrollListener.

到目前为止,我已经尝试了很多不同的代码组合,我不能在这里发布它们.以下是对我有用的(但只是部分):

public void smoothUserScrollTo(final int position) {

    if (position < 0 || position > getAdapter().getItemCount()) {
        Log.e(TAG, "An attempt to scroll out of adapter size has been stopped.");
        return;
    }

    if (getLayoutManager() == null) {
        Log.e(TAG, "Cannot scroll to position a LayoutManager is not set. " +
                "Call setLayoutManager with a non-null layout.");
        return;
    }

    if (getChildAdapterPosition(getCenterView()) == position) {
        return;
    }

    stopScroll();

    scrollToPosition(position);

    if (lastScrollPosition == position) {

        addOnLayoutChangeListener(new OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {

                if (left == oldLeft && right == oldRight && top == oldTop && bottom == oldBottom) {
                    removeOnLayoutChangeListener(this);

                    updateViews();

                    // removing the following line causes a position - 3 effect.
                    scrollToView(getChildAt(0));
                }
            }
        });
    }

    lastScrollPosition = position;
}

@Override
public void scrollToPosition(int position) {
    if (position < 0 || position > getAdapter().getItemCount()) {
        Log.e(TAG, "An attempt to scroll out of adapter size has been stopped.");
        return;
    }

    if (getLayoutManager() == null) {
        Log.e(TAG, "Cannot scroll to position a LayoutManager is not set. " +
                "Call setLayoutManager with a non-null layout.");
        return;
    }

//      stopScroll();

        ((LinearLayoutManager) getLayoutManager()).scrollToPositionWithOffset(position, 0);
//        getLayoutManager().scrollToPosition(position);
    }
Run Code Online (Sandbox Code Playgroud)

我选择了scrollToPositionWithOffset()因为这个,但情况可能不同,因为我使用LinearLayoutManager而不是GridLayoutManager.但是这个解决方案对我也有用,但正如我之前所说的那样,只是部分解决了.

  • 当滚动调用从第0位到totalSize时 - 7滚动就像一个魅力.
  • 当滚动从totalSize - 7到totalSize - 3时,首次我只滚动到列表中的第7个最后一项.然而第二次我可以滚动好
  • 从totalSize - 3滚动到totalSize时,我开始出现意外行为.

如果有人找到了解决方法我会欣赏它.这是我的自定义代码的要点ReyclerView.

Rob*_*yai 42

几个星期前我遇到了同样的问题,发现只有一个非常糟糕的解决方案.不得不postDelayed用200-300ms.

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        yourList.scrollToPosition(position);
    }
}, 200);
Run Code Online (Sandbox Code Playgroud)

如果您找到了更好的解决方案,请告诉我们!祝好运!

  • 最好使用`myRecycleView.post(() -&gt; myRecycleView.smoothScrollToPosition(position))` (4认同)
  • 虽然我也认为这种解决方案是粗略的,但这是迄今为止唯一可行的解​​决方案:不管怎么说,还是要谢谢你! (2认同)
  • 这是唯一有效的解决方案.首先我调用了chatAdapter.notifyDataSetChanged(); 然后是新的Handler().postDelayed(new Runnable(){@Override public void run(){if(list_chat.size()> 0){recyclerView.smoothScrollToPosition(list_chat.size() - 1);}}},200 ); (2认同)
  • 似乎有些东西与OnCreate()并行运行,它会重置滚动位置.当您在OnCreate()或OnResume()或OnStart()中设置滚动位置而没有延迟时,它会被这个神秘的并行进程覆盖.我在调试模式下尝试了这个并在scrolltoposition()方法之前和之后逐步完成代码并且它工作正常,大概是因为通过逐行运行代码我引入了一个延迟,让这个神秘的并行进程在运行scrolltoposition之前完成() 方法.我认为这就是为什么这里给出的答案有效. (2认同)
  • 我发现的解决方案是在UI线程上运行对setAdapter的调用(使用与我已经使用的适配器相同的适配器),然后调用notifyDataSetChange,然后从我正在使用的后台线程调用myRecycleView.post(.。带有scrollToPosition的...。感觉像是伏都教徒,但对我有用。 (2认同)

小智 15

结果我在使用之前遇到了类似的问题

myRecyclerview.scrollToPosition(objectlist.size()-1)
Run Code Online (Sandbox Code Playgroud)

当只放入对象列表大小时,它总是保持在顶部.直到我决定将大小设置为变量.再次,这不起作用.然后我假设它可能是在没有告诉我的情况下处理一个outofboundsexception.所以我把它减去1.然后就可以了.

  • 我想知道为什么smoothScrollToPosition()工作,但scrollToPosition()没有,这就是答案!平滑的滚动一定不要关心我试图滚动超出列表的长度所以它无论如何都有效.非常感谢你,我从来没有注意到这是问题所在! (2认同)

Har*_*nan 14

接受的答案会起作用,但也可能会中断。此问题的主要原因是当您要求它滚动时,回收器视图可能尚未准备好。最好的解决方案是等待回收器视图准备好然后滚动。幸运的是 android 提供了一个这样的选项。以下解决方案适用于 Kotlin,您可以尝试同样的 java 替代方案,它会起作用。

newsRecyclerView.post {
    layoutManager?.scrollToPosition(viewModel.selectedItemPosition)
}
Run Code Online (Sandbox Code Playgroud)

post runnable 方法可用于每个 View 元素,并且会在视图准备好后执行,从而确保代码在需要时准确执行。


Sur*_*nav 8

LinearSmoothScroller在我的情况下,您每次都可以使用它:

  1. 首先创建一个 LinearSmoothScroller 的实例:
  LinearSmoothScroller smoothScroller=new LinearSmoothScroller(activity){
            @Override
            protected int getVerticalSnapPreference() {
                return LinearSmoothScroller.SNAP_TO_START;
            }
        };
Run Code Online (Sandbox Code Playgroud)
  1. 然后,当您想将回收站视图滚动到任何位置时,请执行以下操作:
smoothScroller.setTargetPosition(pos);  // pos on which item you want to scroll recycler view
recyclerView.getLayoutManager().startSmoothScroll(smoothScroller);
Run Code Online (Sandbox Code Playgroud)

完毕。


lit*_*tex 8

我也遇到了类似的问题(当列表更新时必须滚动到顶部),但上述选项都没有 100% 有效

不过,我终于在https://dev.to/aldok/how-to-scroll-recyclerview-to-a-certain-position-5ck4 存档链接找到了一个可行的解决方案

概括

scrollToPosition似乎只有在底层数据集准备好时才有效。

因此,它postDelay可以(随机)工作,但这取决于设备/应用程序的速度。如果超时太短,则会失败。smoothScrollToPosition也仅在适配器不忙时有效。

要观察数据集何时准备好,AdapterDataObserver可以添加 a 并重写某些方法。

解决我的问题的代码:

adapter.registerAdapterDataObserver( object : RecyclerView.AdapterDataObserver() {
    override fun onItemRangeInserted(
        positionStart: Int,
        itemCount: Int
    ) {
        // This will scroll to the top when new data was inserted
        recyclerView.scrollToPosition(0)
    }
}
Run Code Online (Sandbox Code Playgroud)


job*_*ert 6

所以对我来说问题是我在NestedScrollView 中有一个RecyclerView。我花了一些时间才弄清楚这是问题所在。对此的解决方案是(Kotlin):

val childY = recycler_view.y + recycler_view.getChildAt(position).y
nested_scrollview.smoothScrollTo(0, childY.toInt())
Run Code Online (Sandbox Code Playgroud)

Java(归功于 Himagi /sf/answers/3525751841/

float y = recyclerView.getY() + recyclerView.getChildAt(selectedPosition).getY();    
scrollView.smoothScrollTo(0, (int) y);
Run Code Online (Sandbox Code Playgroud)

诀窍是将嵌套的滚动视图滚动到 Y 而不是 RecyclerView。这在 Android 5.0 Samsung J5 和带有 Android 9 的华为 P30 pro 上运行良好。


Jij*_*dan 5

这些方法似乎都不适合我。只有下面的一行代码有效

((LinearLayoutManager)mRecyclerView.getLayoutManager()).scrollToPositionWithOffset(adapter.currentPosition(),200);
Run Code Online (Sandbox Code Playgroud)

第二个参数指的是offset,实际上是item view的起始边缘与RecyclerView的起始边缘之间的距离(以像素为单位)。我为它提供了一个常量值,以使顶部的项目也可见。

此处查看更多参考


归档时间:

查看次数:

31188 次

最近记录:

6 年,2 月 前