實現 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)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章