この記事に登場するもの
- ViewPager2
- FragmentStateAdapter
- DiffUtil
- 削除がなんかズレる
AndroidDeveloper
ViewPager2ざっくり実装部分
MyFragmentがViewPagerを保持し、1つ1つのPageFragmentが削除ボタンでadapterに削除をかける想定。
PagerAdapterはDiffUtilを使って画面を更新する。
※この実装だと、削除すると1つずれたページが何故か削除される。
MyFragment.kt
lateinit var pagerAdapter: PagerAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
pagerAdapter = PagerAdapter(this, pageList)
binding.viewPager.apply {
adapter = pagerAdapter
}
}
PagerAdapter.kt
private val list = mutableListOf<PageItem>()
override fun getItemCount() = list.size
override fun createFragment(position: Int) = PageFragment.newInstance(list[position])
fun refresh(newList: MutableList<PageItem>) {
val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return list.size
}
override fun getNewListSize(): Int {
return newList.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return list[oldItemPosition].name == newList[newItemPosition].name
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return list[oldItemPosition].name == newList[newItemPosition].name
}
})
list.clear()
list.addAll(newList)
diff.dispatchUpdatesTo(this)
}
PageFragment.kt
binding.deleteButton.setOnClickListener {
val newList = viewModel.deletePage()
(parentFragment as MyFragment).pagerAdapter.refresh(newList)
}
解決策
PagerAdapterに以下を実装する
PagerAdapter.kt
override fun containsItem(itemId: Long): Boolean {
return list.map {
it.hashCode().toLong()
}.contains(itemId)
}
override fun getItemId(position: Int): Long {
return list[position].hashCode().toLong()
}
実はAndroidDeveloperの真ん中らへんにしっかり書いてあるのだが、こんなの気づかないよ。。。
注: DiffUtil ユーティリティ クラスは、ID に基づくアイテムの識別に依存します。ViewPager2 を使用して編集可能コレクションのページングを行う場合は、getItemId() と containsItem() もオーバーライドする必要があります。
また、getPageWidth() メソッドは、ViewPager2 ではサポートされていません。現在 ViewPager で getPageWidth() を使用して隣接ページへのピーキングを有効にしている場合は、代わりに、RecyclerView の clipToPadding 属性を使用する必要があります。詳細については、サンプルアプリをご覧ください。