说到指定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掉。这样可以解决首次进入页面不能滚动到指定位置的问题了。