RecyclerView:アイテムの出現アニメーション(LayoutAnimation)

投稿日:  更新日:

RecyclerViewへアイテムが表示されるとき、アニメーションはありません。。一瞬で表示されて終わりです。

「RecyclerViewへアイテムが表示される」ことを、ここでは「アイテムの出現」と言い表すことにします。

このアイテムの出現にアニメーションを付ける方法を紹介します。

アイテムの出現をアニメーションで演出することで、RecyclerViewに表示したい内容が際立つと思います。

スポンサーリンク

出現アニメーションとは

アイテムの出現アニメーションとは次のようなものです。

この出現アニメーションを実現するためにLayoutAnimationという仕組みを使います。

スポンサーリンク

LayoutAnimation

LayoutAnimationとは

LayoutAnimationはViewGroup(コンテナタイプのView)が持つアニメーションの仕組みです。ViewGroup内の子Viewが表示される時にViewAnimationを付けて表示します。

Constraint・Linear・FrameLayoutやRecyclerViewは全てViewGroupのサブクラスなので、LayoutAnimationの適応が可能です。

例えば、ConstraintLayoutに「拡大しながら不透明になる」アニメーションを付けると次のようになります。


ImageViewが中央から広がる表示です。若干の時間差があり、左上⇒右上⇒左下⇒右下の順番でアニメーションが進んでいます。

静的な記述方法(xmlに記述)

LayoutAnimationの静的な記述方法は、xmlへ記述してリソースとして扱う方法です。

ViewGroup(ConstraintLayout)のlayoutAnimation属性へ、xmlで定義したLayoutAnimationを指定するだけです。

アニメーションのxmlはres/animフォルダ以下に配置する決まりになっています。

    ...
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/layBlock"
        android:layoutAnimation="@anim/block_appearance"
        ...>

        <ImageView
            android:id="@+id/imgA"
            android:background="@android:color/holo_blue_dark"
            ... />
        <ImageView
            android:id="@+id/imgB"
            android:background="@android:color/holo_green_dark"
            ... />
        <ImageView
            android:id="@+id/imgC"
            android:background="@android:color/holo_orange_dark"
            ... />
        <ImageView
            android:id="@+id/imgD"
            android:background="@android:color/holo_red_dark"
            ... />
			
    </androidx.constraintlayout.widget.ConstraintLayout>
	...
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/scale_up"
    android:delay="15%"
    android:animationOrder="normal"/>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_mediumAnimTime">
    <scale
        android:fromXScale="0%"
        android:toXScale="100%"
        android:fromYScale="0%"
        android:toYScale="100%"
        android:pivotX="50%"
        android:pivotY="50%"/>
    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0"/>
</set>

LayoutAnimationの属性は表に示した意味があります。必要に応じて変更すれば出現の様子が変えられます。詳細はLayoutAnimationControllerのドキュメントを参照してください。

属性(android:XXX)動作/例
animationViewAnimationを指定
android:animation="@anim/scale_up"
animationOrderアニメーションを開始するViewの順番
 normal:indexの昇順(デフォルト)
 random:ランダム
 reverse:indexの降順
android:animationOrder="normal"
delayアニメーションを開始するタイミングの遅延
 %:前Viewのアニメーションが?%進んだところでスタート
 %p:親Viewのアニメーションが?%進んだところでスタート
android:delay="15.0%"
interpolator初期値~最終値までの補間方法のタイプ
 インターポレータのリソースID
android:interpolator="@android:anim/decelerate_interpolator"

ViewAminationは詳細を取り上げません。ViewAnimationのドキュメントを参照してください。(AlphaAnimationAnimationSetRotateAnimationScaleAnimationTranslateAnimation

動的な記述方法(プログラム中に記述)

LayoutAnimationの動的な記述方法は、プログラムで記述する方法です。

静的な記述方法と全く同じ出現アニメーションのプログラムです。

    ...
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/layBlock"
        ...>

        <ImageView
            android:id="@+id/imgA"
            android:background="@android:color/holo_blue_dark"
            ... />
        <ImageView
            android:id="@+id/imgB"
            android:background="@android:color/holo_green_dark"
            ... />
        <ImageView
            android:id="@+id/imgC"
            android:background="@android:color/holo_orange_dark"
            ... />
        <ImageView
            android:id="@+id/imgD"
            android:background="@android:color/holo_red_dark"
            ... />
			
    </androidx.constraintlayout.widget.ConstraintLayout>
	...
				...
				val _layBlock = findViewById<ConstraintLayout>(R.id.layBlock)

                // ViewAnimationの作成
                val _scaleAnim = ScaleAnimation(
                    0.0f, 1.0f, 0.0f, 1.0f,
                    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f)
                val _alphaAnim = AlphaAnimation(0.0f, 1.0f)
                val _animSet = AnimationSet(false).apply {
                    addAnimation(_scaleAnim)
                    addAnimation(_alphaAnim)
                    duration = resources.getInteger(
					    android.R.integer.config_mediumAnimTime).toLong()
                }
                // LayoutAnimationの作成
                val _layAnim = LayoutAnimationController(_animSet).apply {
                    delay = 0.15f
                    order = LayoutAnimationController.ORDER_NORMAL
                }
                // LayoutAnimationの指定
                _layBlock.layoutAnimation = _layAnim
				...

プログラムで記述すると煩雑になるので、アニメーションを分離して管理できる静的な記述方法をお勧めします。

出現の順番(開始するViewの順番)

ViewGroup内に表示する子Viewはインデックス番号を持っています。

ViewGroupはインデックス番号の昇順に子Viewを表示していくので、出現アニメーションも自ずとその順番に開始されます。

ただし、出現アニメーションの順番はデフォルトの場合です。意図的な変更(animationOrderを使用)も可能です。

インデックス番号の付けられ方は、レイアウトxmlであれば記述順、プログラムであればViewGroup#addViewメソッドの実行順になります。

    ...
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/layBlock"
        ...>

        <ImageView                                               <-- index:0
            android:id="@+id/imgA"
            android:background="@android:color/holo_blue_dark"
            ... />
        <ImageView                                               <-- index:1
            android:id="@+id/imgB"
            android:background="@android:color/holo_green_dark"
            ... />
        <ImageView                                               <-- index:2
            android:id="@+id/imgC"
            android:background="@android:color/holo_orange_dark"
            ... />
        <ImageView                                               <-- index:3
            android:id="@+id/imgD"
            android:background="@android:color/holo_red_dark"
            ... />
			
    </androidx.constraintlayout.widget.ConstraintLayout>
	...

出現の遅延(開始するタイミングの遅延)

animation:delay属性の値は図のような関係になっています。

【animation:delay=”15%”を指定】
LayoutAnimationのdelay属性

delayはアニメーション時間の全体に対する割合です。

繰り返したい時

LayoutAnimationはViewGroup内の子Viewが表示される時にViewAnimationを付けて表示します。

この子Viewが表示されるタイミングは2つあります。

  • (1)アプリが起動してViewGroupが表示された時
  • (2)View#requestLayoutを発行して再表示した時

(1)のタイミングはLayoutAnimationによりアニメーションが実行されます。これは、今まで動画サンプルで見てきた通りです。

しかし、(2)のタイミングはアニメーションが実行されません。LayoutAnimationは1回のみ有効だからです。

これを2回以降も有効にしたい場合は、子Viewの表示が始まる前にViewGroup#scheduleLayoutAnimationを実行します。

		...
		val _layBlock = findViewById<ConstraintLayout>(R.id.layBlock)

        findViewById<Button>(R.id.btnRelayout).setOnClickListener {
            _layBlock.requestLayout()			// 再表示の依頼
            _layBlock.scheduleLayoutAnimation() // LayoutAnimationのスケジュール
        }
		...

ちなみに、RecyclerViewのアイテムを更新(全データの変更)する場合、Adapter#notifyDataSetChangedで通知を行いますが、内部でView#requestLayoutが実行されています。よって、同じことが言えます。

スポンサーリンク

RecyclerViewへ組み込み

RecyclerViewはViewGroupのサブクラスなので、LayoutAnimationが使用できます。

RecyclerViewへランキングを表示することを想定して、出現アニメーションを使った演出を行ってみました。

ベストテン(昔々の音楽番組)世代の私としていは、ランキングと言えば下位から上位に向かって、下から積み上がっていくイメージです。

        ... // ↓ 「LayoutAnimationを指定」の部分のみをプログラムから行う
        rcySample.layoutAnimation =
            AnimationUtils.loadLayoutAnimation(this@MainActivity, R.anim.item_appearance)
		...
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/slide_in_top"
    android:delay="20%"
    android:animationOrder="reverse"/>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_longAnimTime">
    <translate android:fromYDelta="-50%p" android:toYDelta="0" />
    <alpha android:fromAlpha="0.0" android:toAlpha="1.0" />
</set>
スポンサーリンク

関連記事:

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の継承、カスタム) 今回は第1回目「ItemAnimator、デフォルト」編です。デフォルト変更アニメーションの動作について説明します。 ...
RecyclerViewでアイテムの変更(Change/Insert/Move/Remove)を行うと、変更される様子がアニメーション化されています。 これはデフォルトでアイテムの変更アニメーションが組み込まれているためです。 デフォルトは単純なアニメーションですが、「ある」と「ない」の違いは歴然で、アニメーションのある方が高価なアプリケーションに見えます。 GUI(Graphical User Interface)が主体の携帯端末にとって、利用者に対するアプリの見せ方は重要です。高価に見えた方が使ってもらえる可能性が高くなります。 上記のことから、アプリの機能に関係なくても、ちょっとした動きをアニメーション化するメリットがあります。 2回にわたりアイテムの変更アニメーションについてまとめてみました。 アイテムの変更アニメーション(DefaultItemAnimator、デフォルト) アイテムの変更アニメーション(SimpleItemAnimatorの継承、カスタム) 今回は第2回目「SimpleItemAnimatorの継承、カスタム」編です。カスタム変更アニメーションの作り方を説明 ...
スポンサーリンク