RecyclerView:アイテムの変更アニメーション(DefaultItemAnimator、デフォルト)

投稿日:  更新日:

RecyclerViewでアイテムの変更(Change/Insert/Move/Remove)を行うと、変更される様子がアニメーション化されています。

これはデフォルトでアイテムの変更アニメーションが組み込まれているためです。

デフォルトは単純なアニメーションですが、「ある」と「ない」の違いは歴然で、アニメーションのある方が高価なアプリケーションに見えます。

GUI(Graphical User Interface)が主体の携帯端末にとって、利用者に対するアプリの見せ方は重要です。高価に見えた方が使ってもらえる可能性が高くなります。

上記のことから、アプリの機能に関係なくても、ちょっとした動きをアニメーション化するメリットがあります。

2回にわたりアイテムの変更アニメーションについてまとめてみました。

今回は第1回目「ItemAnimator、デフォルト」編です。デフォルト変更アニメーションの動作について説明します。

スポンサーリンク

デフォルト変更アニメーション(DefaultItemAnimator)

アイテムの変更アニメーションはItemAnimatorクラスが行っています。
(※ItemAnimatorは抽象クラスなので継承先のクラスへ動作が実装されるている)

ItemAnimatorのインスタンスをRecyclerViewの中で格納しているのがmItemAnimatorフィールドです。

このmItemAnimatorは、RecyclerViewのインスタンス作成時に、DefaultItemAnimatorクラスのインスタンスで初期化されます。

public class RecyclerView extends ViewGroup implements ScrollingView,
        NestedScrollingChild2, NestedScrollingChild3 {
    ...
    ItemAnimator mItemAnimator = new DefaultItemAnimator();
	...
}

つまり、DefaultItemAnimatorが変更アニメーションのデフォルトです。

スポンサーリンク

デフォルト変更アニメーションの動作

デフォルト変更アニメーション(DefaultItemAnimator)は次に示すような単純なものです。

【 Change 】ポジション:2を変更
(同時にフェードイン・アウト)

【 Insert 】ポジション:2へ追加
(移動で空欄を作り⇒フェードイン)

【 Move 】ポジション:1から3へ移動
(同時に移動)

【 Remove 】ポジション:2を削除
(フェードアウト⇒移動で空欄を埋める)

スポンサーリンク

デフォルト変更アニメーションの仕組み

前述のとおり、アイテムの変更アニメーションはItemAnimatorクラスが行っています。

ただし、アニメーションはItemAnimatorの単独ではなく、RecyclerViewとItemAnimatorの連携で成り立っています。

アニメーション実行の手順

変更アニメーションは次のような手順で実行されています。

  • (0)アイテム変更の通知を受け取る
  • (1)アイテム変更の内容をアニメーションへ分解
  • (2)アニメーションのリクエストを登録、実行を要求
  • (3)画面リフレッシュタイミングでアニメーション実行

変更アニメーションの仕組み

ItemAnimatorは抽象クラスなので、継承先のクラスでボックス内の動作を実装しなければなりません。

(0)アイテム変更の通知を受け取る

RecyclerViewでアイテムの変更を行う場合、アイテムのデータを変更した後に、変更内容に合った通知(notifyItemXXXの呼出:XXXは変更内容)を行うことになっています。

notifyItemXXXが呼び出されると、RecyclerViewDataObserver内のメソッド(onItemXXX:xxxは変更内容)が実行されます。

onItemXXXメソッドはRecyclerViewへ変更内容を通達し、triggerUpdateProcessorメソッドを実行します。

(1)アイテム変更の内容をアニメーションへ分解

triggerUpdateProcessorメソッドの仕事は、アイテム変更の内容をアイテム毎のアニメーションへ分解することです。

図は変更内容「ポジション2を削除」をアニメーションへ分解する例です。

変更内容をアニメーションへ分解

  • Item2を消す   –> animateDisappearanceを呼び出し
  • Item3を上に移動 –> animatePersistenceを呼び出し
  • Item4を上に移動 –> animatePersistenceを呼び出し
  • Item5を上に移動 –> animateAppearanceを呼び出し

分解されたアニメーションに対応したメソッドを呼び出します。

(2)アニメーションのリクエストを登録、実行を要求

RecyclerViewから呼出される以下のメソッドは抽象メソッドです。

    public abstract static class ItemAnimator {
        ...
        public abstract boolean animateDisappearance(
		        ViewHolder viewHolder,
                ItemHolderInfo preLayoutInfo, ItemHolderInfo postLayoutInfo);
        public abstract boolean animateAppearance(
		        ViewHolder viewHolder,
                ItemHolderInfo preLayoutInfo, ItemHolderInfo postLayoutInfo);
		 public abstract boolean animatePersistence(
		        ViewHolder viewHolder,
                ItemHolderInfo preLayoutInfo, ItemHolderInfo postLayoutInfo);
		public abstract boolean animateChange(
		        ViewHolder oldHolder,ViewHolder newHolder,
                ItemHolderInfo preLayoutInfo, ItemHolderInfo postLayoutInfo);
		...
    }

メソッドの中でアニメーションのリクエストをリストへ登録する実装が求められます。

リクエストのフォーマットやリストの管理方法は実装に任せられています。

メソッド呼出の場面アニメーション動作(リクエスト内容)
animateDisappearanceアイテムが消去・その場で消える(Remove)
・表示範囲外へ移動(Move)
animateAppearanceアイテムが出現・その場で現れる(Add)
・表示範囲内へ移動(Move)
animatePersistenceアイテムの表示継続・表示範囲内で移動(Move)
animateChangeアイテムの交換・旧:その場で消える(Change)
・新:その場で現れる(Change)

また、メソッドの戻り値はbooleanになっていて、true/falseは次のような意味を持ちます。

  • true : runPendingAnimationsの呼出(アニメーションの実行)を要求する
  • false: runPendingAnimationsの呼出(アニメーションの実行)を要求しない

(3)画面リフレッシュタイミングでアニメーション実行

(2)の4つの抽象メソッドからtrueが返されると、View#postOnAnimationを使ってrunPendingAnimationsメソッドの呼び出しがスケジュールされます。

ここで重要なのがView#postOnAnimationです。

Andoridはテレビのように一定の間隔で画面を更新(リフレッシュ)しています。その更新の頻度をフレームレート[fps](1秒間に更新される画面数)と言い、Androidは60[fps]を目標に動いています。

「目標」と書いたのは60[fps]が達成できない場合もあるからです。リフレッシュはUI(メイン)スレッドが制御しているので、UIスレッドが他の重い処理(長時間の処理)を行っている場合などに遅れるからです。

View#postOnAnimationは次のリフレッシュのタイミングでRunnable#runメソッドを実行します。

画面リフレッシュタイミングでアニメーション実行

runPendingAnimationsは抽象メソッドです。メソッドの中でアニメーションを実行する実装が求められます。

スポンサーリンク

デフォルト変更アニメーションの継承関係

DefaultItemAnimatorはItemAnimator抽象クラスを直接継承していません。

間にSimpleItemAnimator抽象クラスを挿みます。

SimpleItemAnimatorの役割は、アニメーションをリクエストに変換することです。

また、後処理の窓口になるdispatchXXXFinishedメソッド(XXXはリクエスト名)が追加されています。

変更アニメーションの継承関係

カスタムItemAnimatorはSimpleItemAnimatorを継承して作成するのが効率的です。

スポンサーリンク

変更アニメーションの変更

アイテムの変更アニメーションをデフォルトから別のものへ変更が可能です。。

そのためのRecyclerView#setItemAnimatorメソッドが用意されています。

    ...
    public void setItemAnimator(@Nullable ItemAnimator animator) {
        if (mItemAnimator != null) {
            mItemAnimator.endAnimations();
            mItemAnimator.setListener(null);
        }
        mItemAnimator = animator;
        if (mItemAnimator != null) {
            mItemAnimator.setListener(mItemAnimatorListener);
        }
    }
	...
    ...
    rcySample.itemAnimator = CustomItemAnimator()
	...

当然、指定するクラスはItemAnimator(またはSimpleItemAnimator)クラスを継承したものです。

スポンサーリンク

関連記事:

RecyclerViewは子Viewを並べて表示するコンテナタイプ(ConstraintLayoutと同じ)のViewです。 複数のデータをスクリーン上に一覧表示したい時、例えば電話帳のような「氏名+住所+電話番号」の一覧を表示する場合などに最適です。 アプリを開発していると一覧表示したいデータが多いことに気付きます。 なのでRecyclerViewはとても重要で重宝するViewです。 しかし、思い通りの表示を行わせるためのテクニックが多すぎて、使いこなしが難しいです。 今まで調べたテクニックを忘れないように、整理して書き残そうと思います。 今回は基本の「RecyclerViewの実装」です。 ...
RecyclerViewでアイテムのクリックイベントを取得し、処理を実行する方法を紹介します。 ...
RecyclerViewはアイテムのレイアウトをアイテム毎に変更できます。その時に使う値がViewTypeです。 ViewTypeでアイテムのレイアウトを変更する方法を紹介します。 ...
RecyclerViewは表示が変更される(アイテムの更新、スクロール)時、アイテムのViewをリサイクル(再生利用)します。 これにより余分なViewの作成が行われなくなり、メモリーの節約とパフォーマンスの向上が望めます。 リサイクルはCachedViewsとRecyclerPoolという2つのキャッシュで行われます。 このキャッシュを使ったリサイクルの動作を調べたので紹介します。 ...
RecyclerViewのリサイクル動作で使われるキャッシュは、サイズを大きくすれば多くのViewHolderが保持できます。その分、多くのメモリを消費します。 ViewHolderを多く保持できたとしても、サイクル動作で効率よく使われなければ、メモリの浪費です。 キャッシュのサイズはRecyclerViewの使われ方よって適切なサイズがあります。 そのため、RecyclerViewはキャッシュのサイズを変更できるようになっています。 ...
RecyclerViewはアイテムを一覧表示してくれます。 ただ一覧表示するだけではなく、「追加・削除・移動・切り替え」といったアイテムの表示を効率よく変更する仕組み持っています。 今回はこの仕組みを使ったアイテムの変更方法を紹介します。 ...
RecyclerViewのリサイクル動作で使われるキャッシュは、サイズを大きくすれば多くのViewHolderが保持できます。その分、多くのメモリを消費します。 ViewHolderを多く保持できたとしても、サイクル動作で効率よく使われなければ、メモリの浪費です。 キャッシュのサイズはRecyclerViewの使われ方よって適切なサイズがあります。 そのため、RecyclerViewはキャッシュのサイズを変更できるようになっています。 ...
RecyclerViewが空(アイテムが無い)の時、EmptyViewを表示する実装を行ったので紹介します。 ...
RecyclerView上のアイテムを選択する方法を紹介します。 外部ライブラリー(AndroidX)で提供されるrecyclerview-selection APIを用いた方法です。 ...
RecyclerViewはListView(RecyclerViewの前身)の時に存在していたChoiceModeがありません。 同様な機能が欲しければプログラマ側で実装しなければなりません。 RecyclerView.AdapterをカスタマイズしてChoiceModeを実装してみたので紹介します。 ...
RecyclerViewはアイテムへ装飾を付けることが出来るようになっています。 装飾とは、例えばアイテムの区切り線などです。 今回はアイテムへ装飾を付ける方法を紹介します。 ...
RecyclerViewに表示しきれなかったアイテムはスクロールを行うことで表示されるようになっています。 スクロールは「外部入力(指でスクリーン上をタッチしてスライド)によるスクロール」の他に、「プログラムによるスクロール」をすることも出来ます。 今回はこのアイテムのスクロールについてまとめてみました。 ...
RecyclerViewはアイテムをスクロールさせて隠れたアイテムを表示できます。 スクロールを止める位置は任意です。 任意であるがゆえに、止めた位置によってはアイテムの一部が欠けてしまうこともあります。 携帯端末の画面は狭いので、効率よくコンテンツの表示を行いたいとアプリ開発者は考えます。 アイテムの一部が欠けてしまうことは、効率が良いとは言えません。 このような問題を解決するために、アイテムのスナップをRecyclerViewへ追加できます。 アイテムのスナップを追加する方法を紹介します。 ...
RecyclerViewでアイテムの変更(Change/Insert/Move/Remove)を行うと、変更される様子がアニメーション化されています。 これはデフォルトでアイテムの変更アニメーションが組み込まれているためです。 デフォルトは単純なアニメーションですが、「ある」と「ない」の違いは歴然で、アニメーションのある方が高価なアプリケーションに見えます。 GUI(Graphical User Interface)が主体の携帯端末にとって、利用者に対するアプリの見せ方は重要です。高価に見えた方が使ってもらえる可能性が高くなります。 上記のことから、アプリの機能に関係なくても、ちょっとした動きをアニメーション化するメリットがあります。 2回にわたりアイテムの変更アニメーションについてまとめてみました。 アイテムの変更アニメーション(DefaultItemAnimator、デフォルト) アイテムの変更アニメーション(SimpleItemAnimatorの継承、カスタム) 今回は第2回目「SimpleItemAnimatorの継承、カスタム」編です。カスタム変更アニメーションの作り方を説明 ...
RecyclerViewへアイテムが表示されるとき、アニメーションはありません。。一瞬で表示されて終わりです。 「RecyclerViewへアイテムが表示される」ことを、ここでは「アイテムの出現」と言い表すことにします。 このアイテムの出現にアニメーションを付ける方法を紹介します。 アイテムの出現をアニメーションで演出することで、RecyclerViewに表示したい内容が際立つと思います。 ...
スポンサーリンク