【问题标题】:How to make auto smooth scroll with offset Recycler View?如何使用偏移回收器视图进行自动平滑滚动?
【发布时间】:2018-10-24 08:51:21
【问题描述】:

有这样的问题,我有水平的RecyclerView,其中每个单元格都小于屏幕的宽度。

所以我在这里找到了解决方案

RecyclerVIew auto scroll to display all the elements as in News Feed etc.,

如果一个单元格占据屏幕的整个宽度,则所有工作都很好,否则(如果每个单元格占据屏幕宽度的 95%)每次自动滑动将单元格放在屏幕的初学者(右侧),这是合乎逻辑的。所以在一个可见单元格的末尾是另一个单元格的开始

看起来不太好。我需要这个单元格像这样位于屏幕的中间。

我需要查看上一个单元格 - 当前单元格 - 下一个单元格

现在我想解释一些我如何制作当前平滑滚动的魔法(正如我在上面的链接中提到的)

这个方法在我的CustomLinnearLayoutManager

@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position)
{
    LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext())
    {
        @Override
        public PointF computeScrollVectorForPosition(int targetPosition)
        {
            return SmoothLayoutManager.this.computeScrollVectorForPosition(targetPosition);
        }

        @Override
        protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics)
        {
            return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
        }
    };

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

但是这个方法可以不用偏移量

我发现了另一种可以提供所需偏移量的方法

scrollToPositionWithOffset(final int position, final int offset)

它看起来正是我所需要的,但这种方法没有流畅的动画效果。

所以,最终我的问题是:如何将动画逻辑从第一种方法应用到第二种方法(带有偏移)

欢迎提问

【问题讨论】:

    标签: java android android-recyclerview


    【解决方案1】:

    要在RecyclerView 的中心自动捕捉并显示一项,只需使用LinearSnapHelper,如下所示:

    LinearSnapHelper snapHelper = new LinearSnapHelper();
    snapHelper.attachToRecyclerView(recyclerView);
    

    如果您想以编程方式滚动到特定项目,LinearSnapHelper 也可以处理捕捉功能。

    SmoothScroller smoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
            @Override
            protected int getVerticalSnapPreference() {
                return LinearSmoothScroller.SNAP_TO_ANY;
            }
    
            @Override
            protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
                return 120f / displayMetrics.densityDpi;
            }
        };
    
    ...
    
    smoothScroller.setTargetPosition(position);
    recyclerView.getLayoutManager().startSmoothScroll(smoothScroller);
    

    这是视觉效果:
    .

    .......................手动滚动.................... .......以编程方式滚动..........

    【讨论】:

    • 是的,这正是我想要的。但是还有一个问题,正如您所看到的,当您首先自动滚动到确切位置时,您会得到这个位置,而不是将这个单元格设置为中心的拉动效应......也许您知道如何在一个流程中做到这一点?没有这种拉动效应...
    • 我已经发布了我的实现。最后我有一个问题(请看一下)。如果您知道如何解决,请告诉我。谢谢
    • 你的意思是你想立即去目标位置?没有遍历动画?
    • 为了避免在列表很大时遍历大量项目,您可以做一个这样的技巧:hastebin.com/imeqidabav.cpp 也可以有多个滚动速度(如您所做的那样)用于遍历各种距离.我的意思是距离可以分为多个部分,具体取决于它的长度,然后每个部分都有自己的速度。 (距离目标位置越近,速度越低)
    • 不完全是。如果您尝试通过手指进行平滑滚动(不快) - 一切都很好,并且单元格实际上像预期的那样来到了中间,但是如果您尝试进行相同的滚动但速度很快,那么在这种情况下,它看起来应该是停止(假设在 20 个单元格之后)实际上它没有......它走得更远......假设 + 20 个单元格......看起来有人继续滚动更多......你在你的实现中看到类似的东西吗?尝试快速滑动手指
    【解决方案2】:

    最终,我找到了方法,非常感谢@aminography 的回答,还有一个回答对我有很大帮助

    https://stackoverflow.com/a/39654328

    其实我现在有这样的实现

    我的自定义LinnearLayoutManager 实现

    public class SmoothLayoutManager extends LinearLayoutManager
    {
    public static final int X_25 = 25;
    public static final int X_200 = 200;
    public static final float DEFAULT = X_25;
    
    /**
     * !! IMPORTANT !!
     * If you need to add new value, don't forget add it here also
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({X_25, X_200})
    private @interface Speed
    {
    
    }
    
    private static float MILLISECONDS_PER_INCH = DEFAULT;
    
    public SmoothLayoutManager(Context context)
    {
        super(context);
    }
    
    public SmoothLayoutManager(Context context, int orientation, boolean reverseLayout)
    {
        super(context, orientation, reverseLayout);
    }
    
    public SmoothLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
    {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
    
    public SmoothLayoutManager setSpeedOfSmooth(@Speed int iSpeed)
    {
        MILLISECONDS_PER_INCH = iSpeed;
    
        return this;
    }
    
    @Override
    public void scrollToPositionWithOffset(final int position, final int offset)
    {
        super.scrollToPositionWithOffset(position, offset);
    }
    
    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position)
    {
        RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(recyclerView.getContext())
        {
            @Override
            public PointF computeScrollVectorForPosition(int targetPosition)
            {
                return SmoothLayoutManager.this.computeScrollVectorForPosition(targetPosition);
            }
    
            @Override
            protected int getVerticalSnapPreference()
            {
                return LinearSmoothScroller.SNAP_TO_ANY;
            }
    
            @Override
            protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics)
            {
                return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
            }
    
            @Override
            public int calculateDtToFit(final int viewStart, final int viewEnd, final int boxStart, final int boxEnd, final int snapPreference)
            {
                return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
            }
        };
    
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }
    }
    

    我就是这样设置的

    private void setRv(Context iC)
        {
            RecyclerView.Adapter adapter = new UpSaleInnerAdapter(mPicasso, mInflater, iLink -> mListener.onButtonClick(iLink));
    
            mRv.setLayoutManager(new SmoothLayoutManager(iC, LinearLayoutManager.HORIZONTAL, false).setSpeedOfSmooth(SmoothLayoutManager.X_200));
            mRv.setAdapter(adapter);
    
            SnapHelper snapHelper = new LinearSnapHelper();
            snapHelper.attachToRecyclerView(mRv);
        }
    

    注意:

    我注意到,有时如果您快速滑动,SnapHelper 会有点困惑,并通过更多需要的单元格......就像涡轮模式:)

    如果有人找到解决方法,请告诉我。

    谢谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-07
      • 2021-05-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多