💤

[Android]ViewPager2で差分変更アニメーションを無効にする

2022/05/19に公開

はじめに

ViewPager2 を RecyclerView の代替として使った時に詰まった事例の解決方法を紹介します。

ViewPager2

ViewPager2 には RecyclerView.Adapter の使用が可能で、いい感じに横スクロールするリストを作る時に RecyclerView の代替として使うことができます。

binding.viewPager2.adapter = HogeRecyclerViewAdapter()

この時、 リストの差分変更アニメーションを無効にしたい場合があります。
いわゆる notifyItemChanged によるチラつきを無くしたい場合などです。

RecyclerView の場合は手っ取り早くアニメーションを無効にする方法として itemAnimator に null を代入したり、 itemAnimator の特定のオプションだけを無効にする方法が使えます。

// 全アニメーション無効
binding.recyclerView.itemAnimator = null
// 差分変更アニメーションのみ無効
(binding.recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false

しかし、 ViewPager2 では itemAnimator を直接参照して設定を変えることができません。

binding.viewPager2.itemAnimator = null // NG!!

ViewPager2 で差分変更アニメーションをどう無効にすればいいのかで1日ぐらい悩みました。

解決方法

以下のように、 空の PageTransformer を ViewPager2 にセットすればアニメーションが無効になります。

binding.viewPager2.setPageTransformer { _, _ -> }

特に空である必要はなく、とにかく何らかの値を渡してあげればいいです。

理由

ViewPager2.setPageTransformer の内部コードを覗いてみます。内部は Java ですが、そんなに難しいコードは出てこないです。

public void setPageTransformer(@Nullable PageTransformer transformer) {
    // ------- ↓注目 -------
    if (transformer != null) {
        if (!mSavedItemAnimatorPresent) {
            mSavedItemAnimator = mRecyclerView.getItemAnimator();
            mSavedItemAnimatorPresent = true;
        }
        // ------- ↓注目 -------
        mRecyclerView.setItemAnimator(null);
    } else {
        if (mSavedItemAnimatorPresent) {
            mRecyclerView.setItemAnimator(mSavedItemAnimator);
            mSavedItemAnimator = null;
            mSavedItemAnimatorPresent = false;
        }
    }
    ...
}

上記の // ------- ↓注目 ------- とした箇所に着目してみてください。

if (transformer != null) {
    ...
    mRecyclerView.setItemAnimator(null);
}

setPageTransformer の引数である transformer が null でない場合、 mRecyclerView.itemAnimator に null がセットされています。

つまり、とにかく ViewPager2.PageTransformer に null 以外の値をセットしてあげれば ViewPager2(をRecyclerViewとして使った場合) のアニメーションが無効になるのです。

処理としてはたったこれだけです。

おわりに

個人的にも 果たしてこれが本当にベストプラクティスなのか? という疑問の残る内容ではありますが、自分と同じように困っている人のために記事を残しておきます。

また、もっとスマートなやり方をご存知の方がいらっしゃいましたら情報提供ぜひお待ちしております。

Discussion