美文网首页Android开发知识小集
RecyclerView滑动到item顶部的解决办法

RecyclerView滑动到item顶部的解决办法

作者: 我啊翔1314 | 来源:发表于2018-09-22 23:47 被阅读338次

    最近在开发的时候,遇到了需要通过代码使得RecyclerView能够滑到指定item顶部位置的需求,在查看源码之后,发现RecyclerView已经提供了实现滑动到指定位置的方法,下面是可实现方法:

    //平滑滚动
    recyclerView.smoothScrollToPosition(position);
    //非平滑滚动
    recyclerView.scrollToPosition(position);
    
    LinearLayoutManager manager = (LinearLayoutManager)recyclerView.getLayoutManager();
    //平滑滚动
    manager.scrollToPosition(position)
    

    当然,除了上述方法以外,RecyclerView还有scrollBy、smoothScrollBy这两个方法(RecyclerView不支持scrollTo),可以实现滑动到指定位置,但是使用这三个方法滑动到对应item位置,需要计算item的高度或宽度,实现起来过于复杂。
    在LayoutManager中,也包含了滚动的方法,且调用对应的方法也能实现滚动:


    调用manager中的滚动方法.png

    实际上,RecyclerView的滑动方法,都是通过代理manager的滑动方法实现的,下面是RecyclerView中smoothScrollToPosition(int position)的源码:

    /**
     * Starts a smooth scroll to an adapter position.
     * <p>
     * To support smooth scrolling, you must override
     * {@link LayoutManager#smoothScrollToPosition(RecyclerView, State, int)} and create a
     * {@link SmoothScroller}.
     * <p>
     * {@link LayoutManager} is responsible for creating the actual scroll action. If you want to
     * provide a custom smooth scroll logic, override
     * {@link LayoutManager#smoothScrollToPosition(RecyclerView, State, int)} in your
     * LayoutManager.
     *
     * @param position The adapter position to scroll to
     * @see LayoutManager#smoothScrollToPosition(RecyclerView, State, int)
     */
    public void smoothScrollToPosition(int position) {
            if (mLayoutFrozen) {
                return;
            }
            if (mLayout == null) {
                Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. "
                        + "Call setLayoutManager with a non-null argument.");
                return;
            }
            layoutManger.smoothScrollToPosition(this, mState, position);
        }
    

    虽然使用LayoutManager中的滚动方法,一样可以实现滑动,但是一般情况下,如果RecyclerView包含与LayoutManager同样的方法,要优先选择使用RecyclerView中的方法。
    好了,废话不多说,下面以smoothScrollToPosition为例,看看调用滑动方法的效果:


    调用smoothScroll方法滚动到指定item.gif

    可以发现,点击对应按钮调用滑动方法时,有时会无效。这是因为默认情况下,如果item可见,调用滑动到该item的方法时,该方法将不执行滑动。这就说明,调用scrollToPosition或者smoothScrollToPosition并不能保证能够滑到item的顶部。这就尴尬了,这个问题该怎么解决呢?
    查阅资料后,发现可以通过下面两种方法解决:

    1.LinearLayoutManger.scrollToPositionWithOffset(int position, int offset)##

    该方法是在LinearLayoutManager中,其中offset为滑动偏移量,当设置offset为0时,会滑动position对应的item的顶部,此方法与scrollToPosition一样,为非平滑滚动:

    LinearLayoutManager manager = (LinearLayoutManager)recyclerView.getLayoutManager();
    manager.scrollToPositionWithOffset(position, 0);
    

    效果如下:


    调用scrollToPositionWithOffset方法.gif

    2.复写LinearSmoothScoller的getVerticalSnapPreference()##

    此解决办法来源于stackOverFlow,只要复写LinearSmoothScroller的getVerticalSnapPreference(),即可实现平滑滚动到指定item顶部。首先我们看看getVerticalSnapPreference()方法:

        /**
         * When scrolling towards a child view, this method defines whether we should align the top
         * or the bottom edge of the child with the parent RecyclerView.
         *
         * @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current target vector
         * @see #SNAP_TO_START
         * @see #SNAP_TO_END
         * @see #SNAP_TO_ANY
         */
        protected int getVerticalSnapPreference() {
            return mTargetVector == null || mTargetVector.y == 0 ? SNAP_TO_ANY :
                    mTargetVector.y > 0 ? SNAP_TO_END : SNAP_TO_START;
        }
    

    看上面的注释,可以知道,SNAP_TO_START代表滑动到item顶部,因此只要使该方法固定返回SNAP_TO_START,就能实现滑动到item顶部:

    package cn.axen.mvp.scroller
    
    import android.content.Context
    import android.support.v7.widget.LinearSmoothScroller
    
    public class TopLinearSmoothScroller extends LinearSmoothScroller {
        public TopLinearSmoothScroller(Context context) {
            super(context)
        }
        
        @Override
        public int getVerticalSnapPreference(): Int {
            return SNAP_TO_START
        }
    }
    

    最后,复写LinearLayoutManager的smoothScrollToPosition方法,调用RecyclerView的smoothScrollToPosition方法:

    LinearLayoutManager manager = new LinearLayoutManager(this) {
        @Override
        public void smoothScrollToPosition(RecyclerView view, RecyclerView.State state, int position) {
            TopLinearSmoothScroller scroller = new TopLinearSmoothScroller(view.getContext());
            scroller.setTargetPosition(position);
            startSmoothScroll(smoothScroller);
        }
    };
    recyclerView.smoothScrollToPosition(position);
    

    效果如下:

    重写后的效果.gif
    参考博客:
    RecyclerView自动滑动到指定的position
    RecyclerView 滑动控制笔记
    RecyclerView-How To smooth scroll to top of item on a certain position?

    相关文章

      网友评论

        本文标题:RecyclerView滑动到item顶部的解决办法

        本文链接:https://www.haomeiwen.com/subject/ntnxoftx.html