RecyclerView 平滑滚动到中心位置。安卓

Posted

技术标签:

【中文标题】RecyclerView 平滑滚动到中心位置。安卓【英文标题】:RecyclerView smoothScroll to position in the center. android 【发布时间】:2016-11-19 20:19:12 【问题描述】:

我正在为我的RecyclerView 使用水平布局管理器。 我需要用下一种方式制作RecyclerView:当单击某个项目时-将smoothScrool 放到该位置并将该项目放在RecyclerView 的中心(如果可能,例如,20 中的10 个项目)。

所以,我对smoothScrollToPosition()没有问题,但是如何将项目放在RecyclerView的中心??

谢谢!

【问题讨论】:

【参考方案1】:

是的,这是可能的。

通过实现RecyclerView.SmoothScroller的方法onTargetFound(View, State, Action)

/**
 * Called when the target position is laid out. This is the last callback SmoothScroller
 * will receive and it should update the provided @link Action to define the scroll
 * details towards the target view.
 * @param targetView    The view element which render the target position.
 * @param state         Transient state of RecyclerView
 * @param action        Action instance that you should update to define final scroll action
 *                      towards the targetView
 */
abstract protected void onTargetFound(View targetView, State state, Action action);

特别是在LinearLayoutManagerLinearSmoothScroller

public class CenterLayoutManager extends LinearLayoutManager 

    public CenterLayoutManager(Context context) 
        super(context);
    

    public CenterLayoutManager(Context context, int orientation, boolean reverseLayout) 
        super(context, orientation, reverseLayout);
    

    public CenterLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) 
        super(context, attrs, defStyleAttr, defStyleRes);
    

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) 
        RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    

    private static class CenterSmoothScroller extends LinearSmoothScroller 

        CenterSmoothScroller(Context context) 
            super(context);
        

        @Override
        public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) 
            return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
        
    

【讨论】:

extends LinearSmoothScroller 必须覆盖computeScrollVectorForPosition() 工作完美 完美,对于其他人,你只需调用recyclerView.smoothScrollToPosition(position);,别忘了设置布局管理器recyclerView.setLayoutManager(layoutManager); onTargetFound() 函数在哪里实现? 但是我不明白你为什么提到这个方法onTargetFound()【参考方案2】:

对答案的改进 - 无需覆盖 LinearLayoutManager

来自上一个答案:

public class CenterSmoothScroller extends LinearSmoothScroller 

    public CenterSmoothScroller(Context context) 
        super(context);
    

    @Override
    public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) 
        return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
    

这里如何使用它:

RecyclerView.LayoutManager lm = new GridLayoutManager(...): // or whatever layout manager you need

...

RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());

smoothScroller.setTargetPosition(position);

lm.startSmoothScroll(smoothScroller);

【讨论】:

对于像我一样困惑的其他人,CenterSmoothScroller 是在接受的答案中找到的一个类。 哈利路亚!花了半天时间尝试了一堆复杂的方法来做到这一点,您的解决方案完美运行。谢谢! 在声明recyclerview时如何获得职位?当用户使用 D-Pad 滚动项目时,我需要将项目置于中心。 @user8944115 这就像一个魅力!谢谢,如果你没有找到类,也许你需要更新你的依赖,在androidx.recyclerview.widget.LinearSmoothScroller 这是正确且简单的解决方案。谢谢【参考方案3】:

以防万一有人在接受的答案中需要类的 Kotlin 等效项

class CenterLayoutManager : LinearLayoutManager 
    constructor(context: Context) : super(context)
    constructor(context: Context, orientation: Int, reverseLayout: Boolean) : super(context, orientation, reverseLayout)
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)

    override fun smoothScrollToPosition(recyclerView: RecyclerView, state: RecyclerView.State, position: Int) 
        val centerSmoothScroller = CenterSmoothScroller(recyclerView.context)
        centerSmoothScroller.targetPosition = position
        startSmoothScroll(centerSmoothScroller)
    

    private class CenterSmoothScroller(context: Context) : LinearSmoothScroller(context) 
        override fun calculateDtToFit(viewStart: Int, viewEnd: Int, boxStart: Int, boxEnd: Int, snapPreference: Int): Int = (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2)
    

【讨论】:

【参考方案4】:

根据@Boda 的回答,如果您想控制平滑滚动速度(以获得更好的动画效果),您可以使用以下方法:

class CenterLayoutManager : LinearLayoutManager 
    constructor(context: Context) : super(context)
    constructor(context: Context, orientation: Int, reverseLayout: Boolean) : super(
        context,
        orientation,
        reverseLayout
    )

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
        context,
        attrs,
        defStyleAttr,
        defStyleRes
    )

    override fun smoothScrollToPosition(
        recyclerView: RecyclerView,
        state: RecyclerView.State,
        position: Int
    ) 
        val centerSmoothScroller = CenterSmoothScroller(recyclerView.context)
        centerSmoothScroller.targetPosition = position
        startSmoothScroll(centerSmoothScroller)
    

    private class CenterSmoothScroller(context: Context) : LinearSmoothScroller(context) 
        override fun calculateDtToFit(
            viewStart: Int,
            viewEnd: Int,
            boxStart: Int,
            boxEnd: Int,
            snapPreference: Int
        ): Int = (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2)

        override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float 
            return MILLISECONDS_PER_INCH / displayMetrics.densityDpi
        
    

    companion object 
        // This number controls the speed of smooth scroll
        private const val MILLISECONDS_PER_INCH = 150f
    

用法:

recyclerView.layoutManager = CenterLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
recyclerView.smoothScrollToPosition(selectedPosition)

【讨论】:

【参考方案5】:

从现在(2019 年 2 月)开始,我可以轻松地在 ListView 中使用此代码

(ListView)word_list_view.smoothScrollToPositionFromTop(your_item_index, center_position.y);

RecyclerView 未验证,我猜应该是一样的。

【讨论】:

不适用于 RecyclerView

以上是关于RecyclerView 平滑滚动到中心位置。安卓的主要内容,如果未能解决你的问题,请参考以下文章

RecyclerView 水平滚动对齐在中心

平滑滚动不适用于 Android RecyclerView 的初始滚动

RecyclerView滑动到指定位置,并置顶

RecyclerView smoothScroll位于中心位置。安卓

仿微信未读RecyclerView平滑滚动定位效果

没有在 RecyclerView 上工作 Notifydatasetchange 与中心选择水平滚动视图?