Android——Recyclerview.scrollTo(int)无效问题解决

说到指定Recyclerview滚动到指定位置大家一定很熟悉,比如说节目续播,进入节目详情页,需要将剧集列表定位到具体某一集。方法很简单,但是现实很残酷,(⊙o⊙)…,坑有点多,好在最终问题都解决了,哈哈。下面就来分享下最近跳坑心路旅程。

Recyclerview滚到指定位置,有两个方法:smoothScrollToPosition(int position)和scrollToPosition(int position),他们的区别是:scrollToPosition直接滚到某个位置 ,没有滚动过程;smoothScrollToPosition类似于手动拖回顶部,有滚动过程;源码看过来:

scrollToPosition(int position):

 /**
     * Convenience method to scroll to a certain position.
     *
     * RecyclerView does not implement scrolling logic, rather forwards the call to
     * {@link android.support.v7.widget.RecyclerView.LayoutManager#scrollToPosition(int)}
     * @param position Scroll to this adapter position
     * @see android.support.v7.widget.RecyclerView.LayoutManager#scrollToPosition(int)
     */
    public void scrollToPosition(int position) {
        if (mLayoutFrozen) {
            return;
        }
        stopScroll();
        if (mLayout == null) {
            Log.e(TAG, "Cannot scroll to position a LayoutManager set. " +
                    "Call setLayoutManager with a non-null argument.");
            return;
        }
        mLayout.scrollToPosition(position);
        awakenScrollBars();
    }

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;
        }
        mLayout.smoothScrollToPosition(this, mState, position);
    }

.从上面两端源码可以看出Recyclerview本身并没有实现smoothScrollToPosition(int position)和scrollToPosition(int position),而是调用LayoutManager中提供的smoothScrollToPosition(int position)和scrollToPosition(int position)方法。所以在调用这两个方法之前请务必保证设置了LayoutManager

其次,请看源码:

if (mLayoutFrozen) {
     return;
}

根据Recyclerview中setLayoutFrozen()方法可知,mLayoutFrozen的作用是:

Enable or disable layout and scroll. After setLayoutFrozen(true) is called, Layout requests will be postponed until setLayoutFrozen(false) is called; child views are not updated when RecyclerView is frozen, {@link #smoothScrollBy(int, int)},{@link #scrollBy(int, int)}, {@link #scrollToPosition(int)} and {@link #smoothScrollToPosition(int)} are dropped; TouchEvents and GenericMotionEvents are dropped; {@link LayoutManager#onFocusSearchFailed(View, int, Recycler, State)} will not be called.

这段话大概的意思就是当mLayoutFrozen为true时,Recyclerview的子view不能被更新,smoothScrollToPosition(int position)和scrollToPosition(int position)方法被停止;

还有个注意点在View未绘制完成时,这两个方法也无效。我猜是因为mLayoutFrozen为true,哈哈,待验证。那么怎么办呢?看代码:

if (setGlobalListener) {
                seriesList.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver
                        .OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        setGlobalListener = false;
                        seriesInfoList.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                        seriesLayoutManager.scrollToPositionWithOffset(curPos, 0);
                    }
                });
            } else {
                seriesLayoutManager.scrollToPositionWithOffset(curPos, 0);
            }

这里要注意用完监听方法一点要remove掉。这样可以解决首次进入页面不能滚动到指定位置的问题了。

猜你喜欢

转载自blog.csdn.net/u012230055/article/details/80009004