Android RecyclerView で空の状態のViewを表示するAdapterDataObserverを作成
はじめに
今回は、RecyclerViewが空の状態に別のViewを表示する方法をご紹介します。
ListViewのEmptyViewみたいなものを想像していただければいいと思います。
ゴールとしては、RecyclerViewに setEmptyView(View)
を呼び出すだけで設定できるまでを目指します。
Step1: レイアウトを作っていく
今回作成したのはシンプルに、「RecyclerView」と「RecyclerViewが空の場合に表示するView」の2つを用意しました。
ここでポイントになるのが、この2つは両方とも match_parent にしている部分です。VISIBLEの状態で正しく表示されないと正しく動作しないので、tools:visibilityなどをつかってしっかりとレイアウトを作成してください。
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" tools:itemCount="6" tools:listitem="@layout/item_message" tools:visibility="gone" /> <LinearLayout android:id="@+id/emptyView" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" tools:ignore="UseCompoundDrawables" tools:visibility="visible"> <ImageView android:layout_width="114dp" android:layout_height="100dp" android:src="@drawable/ic_message_placeholder" android:tint="#aaaaaa" tools:ignore="ContentDescription" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="メッセージはありません" android:textColor="#aaaaaa" android:textSize="14sp" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>
Step2: RecyclerView AdapterDataObserver をカスタム
RecyclerViewにはアイテムの変更を監視してくれている、「AdapterDataObserver」というものがあります。
今回はこれを使用して、アイテムが0個になった時を検知していきましょう。
実際に判定しているのは checkIfEmpty()
ですが、「初期化時」「アイテム挿入時」「アイテム削除時」にそれぞれ判定をいれています。
「初期化時」・・・EmptyViewが設定された時
「アイテム挿入時」・・・RecyclerViewにアイテムが追加された時
「アイテム削除時」・・・RecyclerViewからアイテムが削除された時
/** * RecyclerViewの空状態を監視 * * @property recyclerView RecyclerView * @property emptyView 空の場合に表示するView */ class RecyclerViewEmptyObserver( private val recyclerView: RecyclerView, private val emptyView: View ) : RecyclerView.AdapterDataObserver() { init { checkIfEmpty() } override fun onChanged() { checkIfEmpty() } override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { checkIfEmpty() } override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) { checkIfEmpty() } /** * 空かどうかを判定してViewの表示状態を切り替える */ private fun checkIfEmpty() { val adapter = recyclerView.adapter if (adapter != null) { val emptyViewVisible = adapter.itemCount == 0 emptyView.visibleOrGone(emptyViewVisible) recyclerView.goneOrVisible(emptyViewVisible) } } }
visibleOrGone
と goneOrVisible
についてはViewのExentionです。
こちらを参考にしていただければわかると思います。
Step2: RecyclerView Extension を作成
RecyclerViewのExtensionに setEmptyView(view: View)
を追加しておきましょう。
こうすることで、ActivityないしFragment側からこれを呼び出すだけで設定が完了します。
注意点としては、これを設定する前に RecyclerView の Adapter は先に設定しておきましょう。
/** * 空の状態のViewを設定 * * @param view View */ fun RecyclerView.setEmptyView(view: View) { val observer = RecyclerViewEmptyObserver(this, view) adapter?.registerAdapterDataObserver(observer) }
結果
以上これだけで、設定が完了です!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) recyclerView.adapter = adapter recyclerView.setEmptyView(emptyView) }
補足
通信などの非同期処理を実行して、アイテムを追加する場合はこの setEmptyView(view: View)
のタイミングを取得完了時に設定してあげればOKです。