Mostrar una vista vacia en RecyclerView AndroidX Kotlin


Ejemplo de como mostrar una vista vacia en un RecyclerView cuando no haya datos, controlado desde el adaptador, para mostrar la vista vacia se implementa sistema de mostrar diferentes vistas.

Layout de vistas, para la vista vacia item_empty.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@android:id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center_horizontal"
        android:padding="8dp"
        android:paddingStart="?listPreferredItemPaddingStart"
        android:paddingEnd="?listPreferredItemPaddingEnd"
        android:text="@string/allowed_devices_empty"
        android:textAppearance="@style/TextAppearance.MaterialComponents.Caption"
        android:textColor="?android:textColorSecondary" />

</RelativeLayout>

Adaptador RecyclerView

Se debe definir las constantes por cada vista

    companion object {
        private val TAG = MyListAdapter::class.java.simpleName
        private const val VIEW_TYPE_EMPTY = 0
        private const val VIEW_TYPE_ITEM = 1
    }

Para determinar que tipo de vista cargar en cada momento, se debe forzar el RecyclerView que cuando no haya datos que permite visualizar una vista, se hace sobrecargando getItemCount()

    override fun getItemCount(): Int {
        return when (val count = dataSet.count()) {
            0 -> 1
            else -> count
        }
    }

Luego para obtener que vista debe aplicarse, si no hay datos la vista vacia VIEW_TYPE_EMPTY y si hay datos la vista normal VIEW_TYPE_ITEM

    override fun getItemViewType(position: Int): Int = if (dataSet.count() == 0) {
        VIEW_TYPE_EMPTY
    } else {
        VIEW_TYPE_ITEM
    }

Debemos crear los ViewHolders para las vistas EmptyViewHolder para la vista vacia y para la vista con datos MyViewHolder

    inner class EmptyViewHolder(itemView: View) : BaseViewHolder<String>(itemView) {
        private val tvText1 = itemView.findViewById(android.R.id.text1) as TextView

        override fun bind(item: String) {
            tvText1.text = item
        }
    }

    inner class MyViewHolder(itemView: View) : BaseViewHolder<DeviceModel>(itemView) {
        private val tvText1 = itemView.findViewById(android.R.id.text1) as TextView
        private val tvText2 = itemView.findViewById(android.R.id.text2) as TextView

        override fun bind(item: DeviceModel) {
            tvText1.text = item.name
            tvText2.text = item.macAddress
        }
    }

En onCreateViewHolder se cargará el layout corresponiente al tipo de vista a mostrar

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType) {
        VIEW_TYPE_EMPTY -> EmptyViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.item_empty, parent, false)
        )
        VIEW_TYPE_ITEM -> MyViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.simple_list_item_2, parent, false)
        )
        else -> throw IllegalArgumentException("Invalid view type")
    }

En onBindViewHolder establecer los datos a mostrar en cada vista

    override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
        if (position != RecyclerView.NO_POSITION) {
            when (holder) {
                is EmptyViewHolder -> holder.bind(emptyText)
                is MyViewHolder -> holder.bind(dataSet[position])
                else -> throw IllegalArgumentException("Invalid ViewHolder")
            }
        }
    }

La carga de datos se hace con la funciñon submitList

    fun submitList(newData: List<DeviceModel>) {

        val needNotifyDataChanged = dataSet.size == 0

        val diffResult = DiffUtil.calculateDiff(MyDiffCallback(dataSet, newData))
        diffResult.dispatchUpdatesTo(this)
        dataSet.clear()
        dataSet.addAll(newData)
        if (needNotifyDataChanged) notifyItemChanged(dataSet.size)
    }

Para vaciar la lista método clearData()

    fun clearData() {
        val size: Int = dataSet.size
        dataSet.clear()
        notifyItemRangeRemoved(0, size)
    }

Su uso

mAdapter.emptyText = "Sin datos"
...
val dataSet: MutableList<DeviceModel> = arrayListOf()
dataSet.add(DeviceModel(true,"aaa22","ff",null,"device1"))
dataSet.add(DeviceModel(true,"bbb","ff",null,"device2"))
dataSet.add(DeviceModel(true,"ccc","ff",null,"device3"))
mAdapter.submitList(dataSet)
...
mAdapter.clearData()

Código

Dejo el código del ejemplo en mi GIT

Publicado por Codelaby

Mobile DevDesigner

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

A %d blogueros les gusta esto: