56

我正在使用带有 GridLayoutManager 的基本 RecyclerView。我观察到 smoothScrollToPosition 和 scrollToPosition 都不能正常工作。

a)使用时smoothScrollToPosition我经常收到错误RecyclerView

“RecyclerView:在平滑滚动时越过了目标位置。”

并且RecyclerView没有正确滚动(通常会错过目标行)。这主要是在我尝试滚动到某行的第一项时观察到的

b)使用时scrollToPosition它似乎工作得很好,但大多数时候我只能看到该行的第一项,其余的不显示。

你能给我一些提示如何使至少其中一种方法正常工作吗?

非常感谢!

4

17 回答 17

77

最后我能够让它工作!LinearLayoutManager.scrollToPositionWithOffset(int, int)成功了。

于 2015-06-15T14:44:10.167 回答
18

我也有同样的问题,但通过自定义 SmoothScroller 设法解决了这个问题

让自定义 LayoutManager 如下

public class CustomLayoutManager extends LinearLayoutManager {
    private static final float MILLISECONDS_PER_INCH = 50f;
    private Context mContext;

    public CustomLayoutManager(Context context) {
        super(context);
        mContext = context;
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView,
        RecyclerView.State state, final int position) {

        LinearSmoothScroller smoothScroller = 
            new LinearSmoothScroller(mContext) {

            //This controls the direction in which smoothScroll looks
            //for your view
            @Override
            public PointF computeScrollVectorForPosition
            (int targetPosition) {
                return CustomLayoutManager.this
                    .computeScrollVectorForPosition(targetPosition);
            }

            //This returns the milliseconds it takes to 
            //scroll one pixel.
            @Override
            protected float calculateSpeedPerPixel
                (DisplayMetrics displayMetrics) {
                return MILLISECONDS_PER_INCH/displayMetrics.densityDpi;
            }
        };

        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }
}

(文档在上面给出的代码中注释)请将上面的LayoutManager设置为recyerview

CustomLayoutManagerlayoutManager = new CustomLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.smoothScrollToPosition(position);

通过使用自定义布局管理器

scrollToPosition 在我的情况下也可以很好地使用,您可以使用

recyclerView.scrollToPosition(position)

另外,如果您想调整 smoothScrollToPosition 的速度,请覆盖

private static final float MILLISECONDS_PER_INCH = 50f;

在自定义布局管理器中。因此,如果我们将值设置为1f,smoothScrollToPosition 会像 scrollToPosition 一样快。增加值会延迟,减少会加快滚动速度。希望这会有用。

于 2016-03-25T20:44:47.373 回答
13

在我的情况下,

mRecyclerView.scrollToPosition(10);

也没有工作。但

mRecyclerView.smoothScrollToPosition(10);

对我来说很好......

于 2017-06-13T11:51:56.540 回答
8

单击 EditText 从 RecyclerView 中的任何位置平滑地向下滚动到底部。

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);
            }
        });
于 2015-11-04T07:40:22.200 回答
7

前面提到的任何解决方案都可能不起作用的另一个原因是,如果您的 RecyclerView 嵌入在 NestedScrollView 中。在这种情况下,您必须调用 NestedScrollView 上的滚动操作。

例如:

nestedScrollview.smoothScrollTo(0,0)
于 2019-11-08T14:23:17.513 回答
2
recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView,new RecyclerView.State(),currentPosition);
于 2019-05-06T11:40:09.970 回答
1

这个扩展非常有用,请尝试。

fun RecyclerView.smoothSnapToPosition(position: Int, snapMode: Int = LinearSmoothScroller.SNAP_TO_START) {
        val smoothScroller = object : LinearSmoothScroller(this.context) {
            override fun getVerticalSnapPreference(): Int = snapMode
            override fun getHorizontalSnapPreference(): Int = snapMode
        }
        smoothScroller.targetPosition = position
        layoutManager?.startSmoothScroll(smoothScroller)
    }
于 2020-08-20T03:18:06.083 回答
1

如何RecyclerView在设备旋转后执行平滑滚动并保存垂直位置:这是适用于我的情况的方法,

public class MainFragment extends Fragment { //OR activity it's //fragment in my case
    ....
 @Override
    public void onLoadFinished(@NonNull Loader<List<Report>> loader, List<Report> objects) { // or other method of your choice, in my case it's a Loader 
    RecyclerView recyclerViewRv = findViewById(........;
         .....
    recyclerViewRv.setAdapter(.....Your adapter);

            recyclerViewRv.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                }

                @Override
                public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    recyclerScrollY = recyclerViewRv. computeVerticalScrollOffset();
                }
            });

    //Apply smooth vertical scroll
    recyclerViewRv.smoothScrollBy(0,recyclerScrollY);
}
    //Save vertical scroll position before rotating devices
    @Override
        public void onSaveInstanceState(@NonNull Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putInt("recyclerScrollY",recyclerScrollY);
        }

    //BackUp vertical scroll position after rotating devices 
    @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if(savedInstanceState != null) {
                recyclerScrollY = savedInstanceState.getInt("recyclerScrollY");
            }
        }
//If you want to perform the same operation for horizontal scrolling just add a variable called recyclerScrollX = recyclerScrollY = recyclerViewRv. computeHorizontalScrollOffset(); then save in bundle
于 2019-05-18T17:12:57.453 回答
1

尝试测量项目的宽度或高度并调用 smoothScrollBy(int dx, int dy)。

于 2017-03-21T14:26:44.097 回答
1

我遇到了一个奇怪的问题,其中smoothScrollToPosition只偶尔工作。

smoothScrollToPosition放入Handler Post Delayed with 1 second delay后,它工作正常。

请参考以下 Kotlin 示例:

Handler().postDelayed({

   recyclerViewObject.smoothScrollToPosition(0) // mention the position in place of 0

}, 1000) // 1000 indicates the 1 second delay.
于 2020-05-19T16:28:09.587 回答
0

调用 recyclerView smoothScroll 无效,因为 recyclerView 本身不处理其布局。

您应该做的是调用布局管理器滚动方法。

这应该看起来像这样

mRecyclerView.getLayoutManager().scrollToPosition(desiredPosition);
于 2015-06-15T13:02:09.733 回答
0

如果您尝试快速滚动到 RecyclerView 顶部的某个位置,只需使用 LinearLayoutManager.scrollToPositionWithOffset 与 0 作为偏移量。

例子:

mLinearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLinearLayoutManager);

mLinearLayoutManager.scrollToPositionWithOffset(myPosition, 0);

smoothScrollToPosition 非常慢。如果您想要快速使用scrollToPositionWithOffset。

于 2018-10-11T01:00:35.020 回答
0

实际上,如果您在 NestedScrollView 中有一个 RecyclerView,那么每次您想要转到 RecyclerView 的开头时都必须使用这两行:

nestedScrollView.smoothScrollTo(0, 0);
layoutManager.scrollToPositionWithOffset(0, 0);

这完全适合我。

于 2020-05-12T07:13:14.947 回答
0

这些答案都不适合我。我需要,smoothScrollToPosition但@Ramz 的回答没有用。我发现它会一直过度滚动,但只会在一个方向上滚动。我发现这似乎是物品装饰师把它扔掉了。我有一个水平布局,我想在每个项目之后添加一个空格,除了最后一个,它不喜欢这种不对称。只要我在每个项目后面加上一个空格,它就起作用了!

于 2021-01-29T20:50:34.187 回答
0

因此,我一直在寻找一种解决方案,以在另一个布局中使用 recyclerview 回到顶部,该布局在其顶部有一个视图(在我的情况下,我有一个带有 TextView 和我的 recyclerview 的 LinearLayout)。因此,平滑滚动只会走到第一项的一半。

这是我所做的,效果非常好(Kotlin 解决方案):

back_to_top.setOnClickListener {
        GlobalScope.launch(Dispatchers.Main) {
            GlobalScope.launch(Dispatchers.Main) {
                recyclerview.layoutManager?.smoothScrollToPosition(recyclerview, RecyclerView.State(), 0)
                delay((recyclerview.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() * 100L)
            }.join()
            recyclerview.scrollToPosition(0)
        }
        back_to_top.visibility = View.GONE
    }
}

在这里我要做的是平滑滚动到第一个元素并将滚动延迟 100 毫秒乘以最后一个可见项目,然后调用 scrollToPosition(0) (正确地转到顶部)

于 2020-10-17T04:30:21.207 回答
0

这对我有用

    Handler().postDelayed({
                    (recyclerView.getLayoutManager() as LinearLayoutManager).scrollToPositionWithOffset( 0, 0)

}, 100)
于 2020-06-17T05:22:59.183 回答
0

当您使用scrollToPosition时,它将显示在回收站视图的顶部。

但是如果你使用smoothScrollToPosition,它会滚动直到它进入Window Visible。这就是为什么当 smoothScool 到下面的项目时,它会在底部显示

于 2019-01-04T11:45:20.620 回答