0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Android】ViewPager2の削除がずれる

Last updated at Posted at 2021-11-22

この記事に登場するもの

  • 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 属性を使用する必要があります。詳細については、サンプルアプリをご覧ください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?