天天看点

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();

}

}

如果有大佬有更好的解决方案,还请指点