(Smooth)ScrollToPosition 不能与 RecyclerView 一起正常工作

Posted

技术标签:

【中文标题】(Smooth)ScrollToPosition 不能与 RecyclerView 一起正常工作【英文标题】:(Smooth)ScrollToPosition doesn't work properly with RecyclerView 【发布时间】:2015-08-30 23:34:52 【问题描述】:

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

a) 在使用smoothScrollToPosition 时,我经常收到来自RecyclerView 的错误

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

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

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

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

非常感谢!

【问题讨论】:

如果你有一个负数位置(例如,你想到达空适配器中的最后一个位置),你会得到一个错误:***.com/questions/57937265/…。 【参考方案1】:

我终于可以让它工作了! LinearLayoutManager.scrollToPositionWithOffset(int, int) 成功了。

【讨论】:

我遇到了类似的问题,该方法也为我解决了问题......但我实际上正在尝试实现smoothScroll。你也是吗? 使用gridLayoutManager.scrollToPositionWithOffset(index, 0) 也为我工作。 是的,LayoutManager.scrollToPosition() 可能效果不佳,但 LinearLayoutManager.scrollToPositionWithOffset() 很好:D 这很神奇。 典型用法是:LinearLayoutManager llm = (LinearLayoutManager) recyclerView.getLayoutManager(); llm.scrollToPositionWithOffset(10, 0); 但请注意,您不再获得smoothScrollToPosition() 拥有的平滑滚动动画。 不工作!与 mRecyclerView.scrollToPosition(position) 相同【参考方案2】:

我也有同样的问题,但通过自定义 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);

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

滚动到位置 在我的情况下你也可以使用

recyclerView.scrollToPosition(position)

如果你想调整smoothScrollToPosition的速度,请覆盖

private static final float MILLISECONDS_PER_INCH = 50f;

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

【讨论】:

scrollToPositionWithOffset 有效,但为了平滑滚动,我需要 Ramz 的回答。【参考方案3】:

就我而言,

mRecyclerView.scrollToPosition(10);

也没有工作。 但是

mRecyclerView.smoothScrollToPosition(10);

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

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

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

例如:

nestedScrollview.smoothScrollTo(0,0)

【讨论】:

拯救了这一天! 谢谢!没有想到这一点,有一段时间遇到了麻烦。【参考方案6】:
recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView,new RecyclerView.State(),currentPosition);

【讨论】:

recyclerView。 smoothScrollToPosition(position) 调用您在评论中描述的方法。你能解释一下你为什么要设置新的状态吗? recyclerView 已经有状态了?【参考方案7】:

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

【讨论】:

【参考方案8】:

设备旋转后如何平滑滚动并保存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

【讨论】:

【参考方案9】:

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

smoothScrollToPosition 放入 Handler Post 之后 延迟 1 秒延迟,效果很好。

参考以下 Kotlin 示例:

Handler().postDelayed(

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

, 1000) // 1000 indicates the 1 second delay.

【讨论】:

【参考方案10】:

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

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)
    

【讨论】:

【参考方案11】:

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

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

这应该看起来像这样

mRecyclerView.getLayoutManager().scrollToPosition(desiredPosition);

【讨论】:

我试过了,但问题仍然存在。应该可以,但不知何故。 RecyclerView 将滚动调用路由到其 LayoutManager 因此这不会改变任何事情,除非引入潜在的 NPE。【参考方案12】:

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

例子:

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

mLinearLayoutManager.scrollToPositionWithOffset(myPosition, 0);

smoothScrollToPosition 非常慢。如果您想快速获得一些东西,请使用 scrollToPositionWithOffset。

【讨论】:

【参考方案13】:

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

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

【讨论】:

【参考方案14】:

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

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

这完全适合我。

【讨论】:

【参考方案15】:

这对我有用

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

, 100)

【讨论】:

【参考方案16】:

所以我一直在寻找一种解决方案,以在另一个布局中使用 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)(正确地转到顶部)

【讨论】:

【参考方案17】:

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

【讨论】:

以上是关于(Smooth)ScrollToPosition 不能与 RecyclerView 一起正常工作的主要内容,如果未能解决你的问题,请参考以下文章

scrollToPosition(),使用片段更新RecyclerView时

Android Leanback 库 Horizo​​ntalGridView scrollToPosition 不起作用

PS问题 smooth选项

如何获得 smooth.spline 的置信区间?

R语言使用pROC包绘制ROC曲线并使用smooth函数绘制平滑的ROC曲线(方法包括:binormaldensityfitdistrlogcondenslogcondens.smooth)

react react-smooth动画