天天看點

android 輔助功能 翻頁,Android RecyclerView自動翻頁方案

其實已經有很多上拉加載更多、或者滑動到底自動加載的自定義RecyclerView,這裡所使用的方案是通用于RecyclerView的,目的就是為了提高代碼複用

通常在app的清單中會使用分頁加載資料,當使用者停止滑動清單到達底部時會加載下一頁資料;為了更好地使用者體驗,可以在清單停止滑動是會提前幾個item加載下一頁資料。

public static void setLoad(@NonNull RecyclerView recyclerView, final OnLoadCallback onLoadCallback) {

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {

int visibleLast = -1;

@Override

public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {

super.onScrollStateChanged(recyclerView, newState);

if(newState == SCROLL_STATE_IDLE){

RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();

if(layoutManager == null){

return;

}

if (layoutManager instanceof LinearLayoutManager) {

visibleLast = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();

} else if (layoutManager instanceof StaggeredGridLayoutManager) {

int[] lastItemArr = ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(null);

if (lastItemArr.length > 0) {

visibleLast = lastItemArr[lastItemArr.length - 1];

}

}

if (recyclerView.getAdapter() != null

&& recyclerView.getAdapter().getItemCount() - 4 <= visibleLast) {

if (onLoadCallback != null) {

onLoadCallback.onLoad();

}

}

}

}

});

if (onLoadCallback != null) {

onLoadCallback.onLoad();

}

}

這個需求代碼還是比較簡單的,基于這個需求,基本實作思路就是為RecyclerView設定滑動監聽,在回調中處理請求下一頁資料的回調。

android 輔助功能 翻頁,Android RecyclerView自動翻頁方案

上面的代碼有個問題,實際使用中onLoadCallback可能會被重複回調

public static void setLoad(@NonNull RecyclerView recyclerView, final OnLoadCallback onLoadCallback) {

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {

int visibleLast = -1;

int totalCount;

boolean allow = true;

@Override

public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {

super.onScrollStateChanged(recyclerView, newState);

if(newState == SCROLL_STATE_IDLE){

RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();

if(layoutManager == null){

return;

}

if (layoutManager instanceof LinearLayoutManager) {

visibleLast = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();

} else if (layoutManager instanceof StaggeredGridLayoutManager) {

int[] lastItemArr = ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(null);

if (lastItemArr.length > 0) {

visibleLast = lastItemArr[lastItemArr.length - 1];

}

}

if(recyclerView.getAdapter() != null){

if(!allow){

allow = totalCount != recyclerView.getAdapter().getItemCount();

}

if (allow && recyclerView.getAdapter().getItemCount() - 4 <= visibleLast) {

if (onLoadCallback != null) {

onLoadCallback.onLoad();

}

}

}

}

}

});

if (onLoadCallback != null) {

onLoadCallback.onLoad();

}

}

這裡添加了一個allow的boolean變量和totalCount,totalCount用于記錄目前adapter中的資料總數,如果totalCount與adapter.getItemCount()不相等,說明資料發生變化,可以再繼續下一次加載。

這種邏輯方式基于請求有資料傳回的基礎之上,如果出現那種請一次有資料更新,再一次沒有,還需要在繼續請求的情況是做不到的,如果有這種比較任性的需求,還是自己控制這個是否可以繼續加載的辨別位比較靠譜

随後,産品又招上我了,說:“為什麼這個頁面自動加載的這麼慢,其他頁面沒有問題?”。這是一個網格清單,當快速滑動都底部時,等待了2s左右的時間才重新整理出來下一頁的資料,這TMD就有點詭異了。

android 輔助功能 翻頁,Android RecyclerView自動翻頁方案

一查發現,RecyclerView快速滑動到底之後,并沒有馬上請求下一頁的資料。RecyclerView在設定為GridLayoutMannager時,RecyclerView快速滑動後繼續慣性滑動到底時,OnScrollListener的onScrollStateChanged()從SCROLL_STATE_SETTLING狀态變更到SCROLL_STATE_IDLE狀态花了1.8~2.4s左右的時間(開始懷疑人生,難道是我打開方式不對?)。

android 輔助功能 翻頁,Android RecyclerView自動翻頁方案

沒招了,隻能将代碼從onScrollStateChanged()放到onScrolled()裡,這樣一來确實有一部分的性能損失,但是這一情況太影響使用者體驗之隻能這麼辦。适當的調整了一下代碼的邏輯,盡量減少無效的findItem計算。

public static void setLoad(@NonNull RecyclerView recyclerView, final OnLoadCallback onLoadCallback, boolean isAuto) {

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {

int visibleLast = -1;

int totalCount;

boolean allow = true;

@Override

public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {

super.onScrolled(recyclerView, dx, dy);

if (recyclerView.getAdapter() != null) {

if (!allow) {

allow = totalCount != recyclerView.getAdapter().getItemCount();

}

}

if (!allow) {

return;

}

RecyclerView.LayoutManager mLayoutManager = recyclerView.getLayoutManager();

if (mLayoutManager == null) {

return;

}

if (mLayoutManager instanceof LinearLayoutManager) {

visibleLast = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();

} else if (mLayoutManager instanceof StaggeredGridLayoutManager) {

int[] lastItemArr = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null);

if (lastItemArr.length > 0) {

visibleLast = lastItemArr[lastItemArr.length - 1];

}

}

if (recyclerView.getAdapter() != null

&& recyclerView.getAdapter().getItemCount() - 4 <= visibleLast

&& allow) {

allow = false;

totalCount = recyclerView.getAdapter().getItemCount();

if (onLoadCallback != null) {

onLoadCallback.onLoad();

}

}

}

});

if (onLoadCallback != null) {

onLoadCallback.onLoad();

}

}

如果有大佬有更好的解決方案,還請指點