【譯】MergeAdapter 的使用 使用官方 API 爲 Recyclerview 添加 Header 和 Footer

原文:Merge adapters sequentially with MergeAdapter
做者:Florina Muntenescu
譯者:Fly_with24java

MergeAdapterrecyclerview 1.2.0-alpha02 中提供的新類,它使您能夠順序組合多個 adapter,以在單個 RecyclerView 中顯示。 這使您能夠更好地封裝 adapter,而沒必要將許多數據源組合到單個 adapter 中,從而使它們集中並複用。android

一個用例是在 Header 或 Footer 中顯示列表加載狀態:當列表從網絡中檢索數據時,咱們想顯示一個進度條。 若是出現錯誤,咱們要顯示錯誤和重試按鈕。git

A RecyclerView with a footer displaying the loading state: progress or error

引入MergeAdapter

MergeAdapter 容許咱們按順序顯示多個 adapter 的內容。 例如,假設咱們有如下 3 個adapter:github

val firstAdapter: FirstAdapter = …
val secondAdapter: SecondAdapter = …
val thirdAdapter: ThirdAdapter = …
val mergeAdapter = MergeAdapter(firstAdapter, secondAdapter, 
     thirdAdapter)
recyclerView.adapter = mergeAdapter
複製代碼

recyclerView 將順序顯示每一個 adapter 中的 item網絡

使用不一樣的 adapter 可使您更好地區分列表的每一個順序部分。 例如,若是要顯示標題,則無需將與標題顯示相關的邏輯放在處理列表顯示的同一 adapter 中,而是能夠將其封裝在其本身的 adapter 中app

RecyclerView and Adapter data

在 Header 和 Footer 中顯示加載狀態

咱們的 Header/Footer 顯示進度或提示錯誤。 列表成功完成加載後,Header/Footer 不該顯示任何內容。 所以,可使用本身的 adapter 將其表示爲包含 0 或 1 個項目的列表:佈局

val mergeAdapter = MergeAdapter(headerAdapter, listAdapter, footerAdapter)

recyclerView.adapter = mergeAdapter
複製代碼

若是 Header/Footer 使用相同的佈局,ViewHolder 和 UI 邏輯(例如顯示進度以及顯示方式),則能夠僅實現一個 adapter 類並建立 2 個實例:一個用於 Header,一個用於 Footer動畫

對於完整的實現,請查看該 pull request,其中添加:ui

  • ViewModel 公開的 LoadState
  • Header 和 Footer 的加載狀態
  • Header 和 Footer 的 ViewHolder 對象
  • 一個 ListAdapter,根據 LoadState 顯示 0 或 1 個 item。 每次 LoadState 更改時,咱們都會通知您須要更改,插入或刪除該 item(請參見代碼

有關MergeAdapter的更多信息

ViewHolders

默認狀況下,每一個 adapter 都維護本身的 ViewHolder pool,而且 adapter 之間不會複用。 若是多個 adapter 顯示相同的 ViewHolder,咱們可能要在它們之間複用同一個實例。 咱們能夠經過使用 MergeAdapter.Config 對象來建立 MergeAdapter 來實現此目的,其中 isolateViewTypes = false。 這樣,全部合併的 adapter 將使用相同的 view pool。 在加載狀態 Header 和 Footer 示例中,兩個 ViewHolder 實際上將顯示相同的內容,所以咱們能夠重複使用它們google

⚠️ 若要支持不一樣的 ViewHolder 類型,應實現 Adapter.getItemViewType。 當您重複使用 ViewHolder 時,請確保相同的 view 類型不會指向不一樣的ViewHolder! 一種最佳實踐是將佈局 id 做爲 view 類型返回。

使用固定的 id

建議不要使用固定的 id 與 notifyDataSetChanged 一塊兒使用,而是建議使用 adapter 的特定通知事件,該事件爲 RecyclerView 提供有關數據集更改的更多信息。 這使 RecyclerView 能夠更有效地更新 UI 並具備更好的動畫。 若是您使用的是 ListAdapter,則在 DiffUtil 回調的幫助下,將在後臺爲您處理 notify 事件。 可是,若是確實須要使用 固定的 id,則 MergeAdapter.Config 爲固定的 id 提供 3 種不一樣的配置:NO_STABLE_IDSISOLATED_STABLE_IDSSHARED_STABLE_IDS。 最後兩個要求您處理 adapter 中的 固定的 id。 請查看 StableIdMode 文檔以獲取有關其工做方式的更多信息

數據變動通知

MergeAdapter 的 adapter 部分調用通知功能時,MergeAdapter 會在更新RecyclerView 以前計算新 item 的位置。

從 RecyclerView 的角度來看,notifyItemRangeChanged 表示 item 相同,只是內容有所更改。 notifyDataSetChanged 表示以前和以後之間沒有任何關係。 所以,咱們沒法將 notifyDataSetChanged 映射到 notifyItemRangeChanged

若是 adapter 調用 Adapter.notifyDataSetChanged,則 MergeAdapter 還將調用Adapter.notifyDataSetChanged,而不是 Adapter.notifyItemRangeChanged。 與 RecyclerView 同樣,一般避免調用 Adapter.notifyDataSetChanged(),而是選擇更精細的更新,或者使用自動執行此操做的 adapter 實現,例如 ListAdapterSortedList

查找 ViewHolder 位置

您過去可能曾經使用過 ViewHolder.getAdapterPosition 來獲取 ViewHolder 在 adapter 中的位置。 如今,由於咱們要合併多個 adapter,因此請使用 ViewHolder.getBindingAdapterPosition()。 若是要獲取最後綁定 ViewHolder 的 adapter,則在共享 ViewHolder 的狀況下,使用 ViewHolder.getBindingAdapter()

若是要順序顯示不一樣類型的數據,這些數據將從封裝在其本身的 adapter 中受益,請開始使用 MergeAdapter。 要對 ViewHolder pool 和 固定的 id 進行高級控制,請使用 MergeAdapter.Config

譯者補充

demo

關於我

我是 Fly_with24

相關文章
相關標籤/搜索