RecyclerView:空の時、EmptyViewを表示

投稿日:  更新日:

RecyclerViewが空(アイテムが無い)の時、EmptyViewを表示する実装を行ったので紹介します。

スポンサーリンク

EmptyViewとは

アイテムの変更が可能なRecyclerViewでアイテムを削除し続けると、最終的にRecyclerViewが空になります。この時、RecyclerViewの表示は空白になってしまいます。

空白は利用者に「バグ?」と誤解を与え兼ねないし、見た目もよくありません。

なので、RecyclerViewが空であることを利用者へ積極的に伝えるべきです。

EmptyViewは積極的に伝えるための手段です。下記はその例になります。

例のようにしておけば、RecyclerViewが空になっても状況がわかります。「利用者へ親切なアプリ」であると言えます。

スポンサーリンク

EmptyViewの実現方法

EmptyViewは図にあるようにRecyclcerViewの上に重ねて配置します。

このEmptyViewのVisibilityを「RecyclerViewが空である・ない」の条件で切り替えます。「空である」であればVISIBLE(表示されている)、「空でない」であればGONE(取り外されている)といった感じです。

切り替えの処理はObserverの中で行うようにします。

Observerはアイテム変更の通知をトリガーに実行します。

EmptyViewの実現方法

スポンサーリンク

EmptyViewの実装

EmptyViewを配置

EmptyViewはViewであれば何でもよいです。サンプルはTextViewにしました。

必ずRecyclerViewの上に表示されるように、レイアウトファイル(***.xml)はRecyclerViewの下へEmptyViewを記述します。

表示はレイアウトファイルの上部に記述されたViewから順番に積み上げられて行くからです。

また、RecyclerViewをEmptyViewで覆い隠すために、EmptyViewの境界(Top,Bottom,Left,Right)をRecyclerViewに合わせます。

サンプルのハイライト部分がその境界の指定です。

<androidx.constraintlayout.widget.ConstraintLayout
    ...
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rcySample"
        android:layout_width="200dp"
        android:layout_height="280dp"
        android:layout_marginTop="24dp"
        android:background="@android:color/darker_gray"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

    <TextView
        android:id="@+id/txtEmpty"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:background="@android:color/holo_orange_light"
        android:gravity="center"
        android:text="リストは空です!"
        android:visibility="visible"
        app:layout_constraintBottom_toBottomOf="@+id/rcySample"
        app:layout_constraintEnd_toEndOf="@+id/rcySample"
        app:layout_constraintStart_toStartOf="@+id/rcySample"
        app:layout_constraintTop_toTopOf="@+id/rcySample" />

    ...
</androidx.constraintlayout.widget.ConstraintLayout>

サンプルのEmptyViewはオレンジ色のバックグラウンドに「リストは空です!」と表示しています。

アイテム変更の通知を取得

記事「RecyclerView:アイテムの変更」で、アダプターへ変更の通知(notifyメソッドの実行)を行うと、AdapterDataObserverのメソッドが実行される話を書きました。

この実行されるAdapterDataObserverに加えて、ユーザ定義のObserverを追加することが出来ます。追加するにはアダプターへObserverの登録が必要です。

Observerは複数登録できることに注意してください。登録の重複を防ぐ対策が必要になります。

サンプルはonStart( )で登録しonStop( )で解放して重複を防いでいます。

    private val observer = object : RecyclerView.AdapterDataObserver() {
        override fun onChanged() {
            checkEmptyOfList()  // EmptyViewのVisibilityを切り替え
        }
        override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
        }
        override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
            checkEmptyOfList()  // EmptyViewのVisibilityを切り替え
		}
        override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
            checkEmptyOfList()  // EmptyViewのVisibilityを切り替え
        }
        override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
            checkEmptyOfList()  // EmptyViewのVisibilityを切り替え
        }
    }
	
    override fun onStart() {
        super.onStart()
        rcySample.adapter?.registerAdapterDataObserver(observer)	// 登録
    }
    override fun onStop() {
        super.onStop()
        rcySample.adapter?.unregisterAdapterDataObserver(observer)	// 解放
    }

アイテム数が変化する可能性のあるメソッドで、EmptyViewのVisibilityを切り替える処理(checkEmptyOfList)を行っています。

notifyメソッドで実行されるAdapterDataObserverのメソッドは次の表を参考にしてください。

notifyメソッド変更箇所observerメソッド
更新notifyDataSetChanged( )全データonChanged
変更notifyItemChanged(position: Int)positiononItemRangeChanged
notifyItemRangeChanged(
  positionStart: Int, itemCount: Int)
positionStartから
itemCount個
挿入notifyItemInserted(position: Int)positiononItemRangeInserted
notifyItemRangeInserted(
  positionStart: Int, itemCount: Int)
positionStartから
itemCount個
削除notifyItemRemoved(position: Int)positiononItemRangeRemoved
notifyItemRangeRemoved(
  positionStart: Int, itemCount: Int)
positionStartから
itemCount個
移動
from⇒to
notifyItemMoved(
  fromPosition: Int, toPosition: Int)
fromPosition
toPosition
onItemRangeMoved
変更
payload付
notifyItemChanged(
  position: Int,
  payload: Any?)
positiononItemRangeChanged
notifyItemRangeChanged(
 positionStart: Int, itemCount: Int,
 payload: Any?)
positionStartから
itemCount個

Visibilityを切り替え

アダプターからアイテム数(itemCount)が取得できます。

アイテム数を条件に「空である・ない」を判定してEmptyViewのVisibilityを切り替えます。

    fun checkEmptyOfList() {
        val _count = rcySample.adapter?.let { it.itemCount }?: 0
        if(_count > 0)
            txtEmpty.visibility = View.GONE		// 空でない
        else
            txtEmpty.visibility = View.VISIBLE	// 空である
    }
	
	override fun onResume() {
        super.onResume()
        checkEmptyOfList()
    }
	
	// ※rcySampel:RecyclerViewのインスタンス
	// ※txtEmpty:EmptyView(例はTextView)のインスタンス

Activityの起動時にEmptyViewのVisibilityを切り替えたければ、Activityのライフサイクル中に行うのが良いでしょう。

サンプルはonResume( )で行っています。

スポンサーリンク

関連記事:

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上のアイテムを選択する方法を紹介します。 外部ライブラリー(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の継承、カスタム」編です。カスタム変更アニメーションの作り方を説明 ...
RecyclerViewへアイテムが表示されるとき、アニメーションはありません。。一瞬で表示されて終わりです。 「RecyclerViewへアイテムが表示される」ことを、ここでは「アイテムの出現」と言い表すことにします。 このアイテムの出現にアニメーションを付ける方法を紹介します。 アイテムの出現をアニメーションで演出することで、RecyclerViewに表示したい内容が際立つと思います。 ...
スポンサーリンク