RecyclerView
這個控件帶來的插件化編程體驗和良好的性能都在不斷吸引大家使用 ta秽澳,github 上已經(jīng)有很多基于 RecyclerView 的開源項目闯睹,并且為 RecyclerView 增加了很多牛逼的 feature。這次担神,我也實現(xiàn)了一個自己的 RecyclerView楼吃。
feature-1 滑動到底部加載更多
其實,實現(xiàn) LoadMore 功能并不難,網(wǎng)上也一堆分享孩锡,這里我主要參考了秋百萬的 cube-sdk 中的 recycler-load-more 分支酷宵。
我的疑惑
當 RecyclerView 中只有一條數(shù)據(jù)時,無論我怎么 scroll(滾動)躬窜,OnScrollListener 里
onScrolled(RecyclerView recyclerView, int dx, int dy)
這個重要的回調(diào)方法 似乎是被誰吃掉了一樣浇垦,再也沒有被觸發(fā)了,這是為什么荣挨?
不科學男韧,斷點調(diào)試大法啟動
同事帶我深入了 RecyclerView 源碼尋找這個方法被吃掉的原因。
// 省略在源碼中的艱辛尋找過程...
最后默垄,定位到了 LinearLayoutManager
里的這個方法
int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getChildCount() == 0 || dy == 0) {
return 0;
}
mLayoutState.mRecycle = true;
ensureLayoutState();
final int layoutDirection = dy > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
final int absDy = Math.abs(dy);
updateLayoutState(layoutDirection, absDy, true, state);
final int freeScroll = mLayoutState.mScrollingOffset;
final int consumed = freeScroll + fill(recycler, mLayoutState, state, false);
if (consumed < 0) {
if (DEBUG) {
// 沒有更多元素可以 scroll 4寺恰!口锭!
Log.d(TAG, "Don't have any more elements to scroll");
}
return 0;
}
final int scrolled = absDy > consumed ? layoutDirection * consumed : dy;
mOrientationHelper.offsetChildren(-scrolled);
if (DEBUG) {
Log.d(TAG, "scroll req: " + dy + " scrolled: " + scrolled);
}
mLayoutState.mLastScrollDelta = scrolled;
return scrolled;
}
分析
看到這里朦前,已經(jīng)清楚很多了,注釋里已經(jīng)說明鹃操,consumed < 0
表明沒有更多元素可以滾動(其實已經(jīng)被內(nèi)部消化了)韭寸。在這種情況下,onScrolled(RecyclerView recyclerView, int dx, int dy)
是不會被調(diào)用的组民!那什么情況下算是沒有更多元素可以滾動呢棒仍?
做個實驗好咯
將刷新時加載的數(shù)據(jù)分別設置為 1、2臭胜、3 條,在 logcat 觀察onScrolled(RecyclerView recyclerView, int dx, int dy)
是否被調(diào)用癞尚。
當屏幕中的 item 數(shù)量多到超出屏幕的時候耸三,這時候的滾動是會觸發(fā)
onScrolled(RecyclerView recyclerView, int dx, int dy)
方法的。屏幕中的 item 完全顯示在屏幕中時浇揩,
onScrolled(RecyclerView recyclerView, int dx, int dy)
是不會被觸發(fā)的仪壮。