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

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

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

谢谢!

【问题讨论】:

    标签: android android-recyclerview linearlayoutmanager


    【解决方案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
        猜你喜欢
        • 1970-01-01
        • 2017-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-09
        • 1970-01-01
        • 1970-01-01
        • 2013-08-04
        相关资源
        最近更新 更多