实现 Paging3 加载最后一页,提示没有更多数据的功能

问题

使用 Paging3 处理分页数据,如果需要在 RecyclerView 底部增加【加载更多】的提示,可以通过调用 PagingDataAdapter 的 withLoadStateFooter() 方法,向其底部添加 LoadStateAdapter 的方式实现。

不过在开发中发现,在 LoadStateAdapter 的 onBindViewHolder() 回调的 LoadState 状态,只有 LoadingError,却没有 NotLoading 状态,这样不能实现【没有更多数据】的状态。

而且 LoadStateAdapter 中 item 展示的时机只有在 LoadingError 的状态下,当加载最后一页后,Paging3 不能给出任何提示,仅仅是不能滑动,这也太挫了吧!

分析

猜测 LoadStateAdapter 中应该有可以控制 item 显示和隐藏的方法,LoadStateAdapter 的源码不多,果然在最后发现了一个可以重写的方法:

/**
 * Returns true if the LoadState should be displayed as a list item when active.
 *
 * By default, [LoadState.Loading] and [LoadState.Error] present as list items, others do not.
 */
open fun displayLoadStateAsItem(loadState: LoadState): Boolean {
    return loadState is LoadState.Loading || loadState is LoadState.Error
}

注释说的很清楚了,默认情况下,LoadState.LoadingLoadState.Error 显示 item,其他状态则不显示。

那我们再来看看,它是用如何利用 displayLoadStateAsItem() 控制 item 的显示与隐藏:

/**
 * LoadState to present in the adapter.
 *
 * Changing this property will immediately notify the Adapter to change the item it's
 * presenting.
 */
var loadState: LoadState = LoadState.NotLoading(endOfPaginationReached = false)
    set(loadState) {
        if (field != loadState) {
            val oldItem = displayLoadStateAsItem(field)
            val newItem = displayLoadStateAsItem(loadState)

            if (oldItem && !newItem) {//旧状态为Loading或Error,新状态为NotLoading
                notifyItemRemoved(0)//隐藏
            } else if (newItem && !oldItem) {//旧状态为NotLoading,新状态为Loading或Error
                notifyItemInserted(0)// 显示
            } else if (oldItem && newItem) {//旧状态为Loading或Error,新状态为Loading或Error
                notifyItemChanged(0)// 显示(刷新)
            }
            field = loadState
        }
    }

item 的显示规则,我已经注释的很清楚了,总结一句话:如果想要展示 item,就需要 newItem 的返回值为 true

解决方案

我们的目标是,在【没有更多数据】时,显示 item,此时 LoadState 的状态是 NotLoading,并且 NotLoading 中有个 endOfPaginationReached 变量,我们看下对它的描述:

endOfPaginationReached - false if there is more data to load in the LoadType this LoadState is associated with, true otherwise. This parameter informs Pager if it should continue to make requests for additional data in this direction or if it should halt as the end of the dataset has been reached.

可以看到当 endOfPaginationReached 为 true 时,表示没有更多数据了。

所以我们只要重写 displayLoadStateAsItem() 方法,就可以实现,【没有更多数据】的提示了:

override fun displayLoadStateAsItem(loadState: LoadState): Boolean {
    return super.displayLoadStateAsItem(loadState)
            || (loadState is LoadState.NotLoading && loadState.endOfPaginationReached)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章