¿Cómo mostrar una vista vacía con un RecyclerView?

271

Estoy acostumbrado a poner una vista especial dentro del archivo de diseño como se describe en la ListActivitydocumentación que se mostrará cuando no haya datos . Esta vista tiene la identificación "android:id/empty".

<TextView
    android:id="@android:id/empty"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/no_data" />

Me pregunto cómo se puede hacer esto con lo nuevo RecyclerView.

JJD
fuente
2
Puede usar github.com/rockerhieu/rv-adapter-states , no solo admite la vista vacía, sino también la vista de carga y la vista de error. Y puede usarlo sin cambiar la lógica del adaptador existente.
Hieu Rocker
20
No es más que fascinante que no parece haber un setEmptyView()método simple contra un RecyclerView...
Subby
Aquí está mi respuesta, consulte este enlace stackoverflow.com/a/58411351/5449220
Rakesh Verma
@Subby, de acuerdo, pero setEmptyView()también tenía desventaja. Al cargar datos, no queríamos mostrar una vista vacía ListView, pero lo hizo. Entonces, tuvimos que implementar algo de lógica. Actualmente uso stackoverflow.com/a/48049142/2914140 .
CoolMind

Respuestas:

306

En el mismo diseño donde se define RecyclerView, agregue elTextView :

<android.support.v7.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical" />

<TextView
    android:id="@+id/empty_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:visibility="gone"
    android:text="@string/no_data_available" />

En la onCreatedevolución de llamada o en la adecuada, verifica si el conjunto de datos que lo alimenta RecyclerViewestá vacío. Si el conjunto de datos está vacío, también RecyclerViewestá vacío. En ese caso, el mensaje aparece en la pantalla. Si no, cambie su visibilidad:

private RecyclerView recyclerView;
private TextView emptyView;

// ...

recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
emptyView = (TextView) rootView.findViewById(R.id.empty_view);

// ...

if (dataset.isEmpty()) {
    recyclerView.setVisibility(View.GONE);
    emptyView.setVisibility(View.VISIBLE);
}
else {
    recyclerView.setVisibility(View.VISIBLE);
    emptyView.setVisibility(View.GONE);
}
slellis
fuente
11
Eso no funciona para mí porque el diseño de la vista del reciclador está inflado en el fragmento, mientras que la decisión de mostrar un diseño de elemento normal o un diseño sin elementos se toma en el adaptador.
JJD
1
@JJD cuando se usa un Fragmento, se aplica lo mismo. Cuando infla su vista de fragmentos, tiene la vista de reciclador y luego otro diseño que se usaría para su vista vacía. Por lo general, en mis fragmentos tendré las siguientes vistas: 1) vista de reciclado, 2) vista vacía y 3) vista de barra de progreso. Por lo general, paso el adaptador sea cual sea la lista, pero según el tamaño de la lista, ocultaré la vista del reciclador y mostraré el vacío o viceversa. Si una vista de reciclaje tiene una lista vacía, entonces no hace nada con ella. Solo ves una vista vacía.
Ray Hunter
1
@stackex La verificación debe estar en la devolución de llamada onCreateView del Fragment o onResume of Activity. De esta manera, la verificación se realizará inmediatamente antes de que se muestre la pantalla al usuario y funcionará para ambos, aumentando o disminuyendo la cantidad de filas en el conjunto de datos.
slellis
2
@Zapnologica Puede hacerlo al revés: use un Eventbus (como greenrobots Eventbus u Otto), luego haga que el Adaptador publique en el eventbus cuando cambie el conjunto de datos. En el fragmento, todo lo que debe hacer es crear un método cuyos parámetros correspondan a lo que el Adaptador está pasando al método Eventbus.post y luego cambiar el diseño en consecuencia. Un enfoque más simple pero también más acoplado es crear una interfaz de devolución de llamada en el adaptador y, al crear el adaptador, haga que el fragmento lo implemente.
AgentKnopf
2
En el diseño obtengo múltiples etiquetas raíz. ¿Cómo se ve su archivo de diseño completo?
powder366
192

Para mis proyectos hice esta solución ( RecyclerViewcon setEmptyViewmétodo):

public class RecyclerViewEmptySupport extends RecyclerView {
    private View emptyView;

    private AdapterDataObserver emptyObserver = new AdapterDataObserver() {


        @Override
        public void onChanged() {
            Adapter<?> adapter =  getAdapter();
            if(adapter != null && emptyView != null) {
                if(adapter.getItemCount() == 0) {
                    emptyView.setVisibility(View.VISIBLE);
                    RecyclerViewEmptySupport.this.setVisibility(View.GONE);
                }
                else {
                    emptyView.setVisibility(View.GONE);
                    RecyclerViewEmptySupport.this.setVisibility(View.VISIBLE);
                }
            }

        }
    };

    public RecyclerViewEmptySupport(Context context) {
        super(context);
    }

    public RecyclerViewEmptySupport(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public RecyclerViewEmptySupport(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void setAdapter(Adapter adapter) {
        super.setAdapter(adapter);

        if(adapter != null) {
            adapter.registerAdapterDataObserver(emptyObserver);
        }

        emptyObserver.onChanged();
    }

    public void setEmptyView(View emptyView) {
        this.emptyView = emptyView;
    }
}

Y deberías usarlo en lugar de RecyclerViewclase:

<com.maff.utils.RecyclerViewEmptySupport android:id="@+id/list1"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    />

<TextView android:id="@+id/list_empty"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Empty"
    />

y

RecyclerViewEmptySupport list = 
    (RecyclerViewEmptySupport)rootView.findViewById(R.id.list1);
list.setLayoutManager(new LinearLayoutManager(context));
list.setEmptyView(rootView.findViewById(R.id.list_empty));
maff91
fuente
2
¿Tomó este código de esta respuesta o de aquí ?
Sufian
@Sufian No, no vi esa respuesta, solo encontré la misma manera. Pero ese código definitivamente se ve más bonito que el mío :)
maff91
2
Intenté combinar esto con FirebaseRecyclerAdapter, no funcionó. Esto se debe a que FirebaseRecyclerAdapter no llama al onChange (del AdapterDataObserver), sino que llama a los métodos onItem *. Para que funcione, agregue: `Override public void onItemRangeRemoved (int positionStart, int itemCount) {// the check} Override public void onItemRangeMoved (int fromPosition, int toPosition, int itemPoition) {// the check} // etc ..`
FrankkieNL
1
¿Por qué verifica si el adaptador es nulo en el observador? si el adaptador es nulo, nunca se debe llamar al observador.
Stimsoni
16
ugh, debo decir que esto es solo el clásico BS de Google. ¿Tengo que implementar esto solo para agregar una vista vacía? ¡Debe incluirse en su SDK cr @ psh1t! ¡Por amor de dios!
Neon Warge
62

Aquí hay una solución que usa solo un adaptador personalizado con un tipo de vista diferente para la situación vacía.

public class EventAdapter extends 
    RecyclerView.Adapter<EventAdapter.ViewHolder> {

    private static final int VIEW_TYPE_EVENT = 0;
    private static final int VIEW_TYPE_DATE = 1;
    private static final int VIEW_TYPE_EMPTY = 2;

    private ArrayList items;

    public EventAdapter(ArrayList items) {
        this.items = items;
    }

    @Override
    public int getItemCount() {
        if(items.size() == 0){
            return 1;
        }else {
            return items.size();
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (items.size() == 0) {
            return VIEW_TYPE_EMPTY;
        }else{
            Object item = items.get(position);
            if (item instanceof Event) {
                return VIEW_TYPE_EVENT;
            } else {
                return VIEW_TYPE_DATE;
            }
        }
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v;
        ViewHolder vh;
        if (viewType == VIEW_TYPE_EVENT) {
            v = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.item_event, parent, false);
            vh = new ViewHolderEvent(v);
        } else if (viewType == VIEW_TYPE_DATE) {
            v = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.item_event_date, parent, false);
            vh = new ViewHolderDate(v);
        } else {
            v = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.item_event_empty, parent, false);
            vh = new ViewHolder(v);
        }

        return vh;
    }

    @Override
    public void onBindViewHolder(EventAdapter.ViewHolder viewHolder, 
                                 final int position) {
        int viewType = getItemViewType(position);
        if (viewType == VIEW_TYPE_EVENT) {
            //...
        } else if (viewType == VIEW_TYPE_DATE) {
            //...
        } else if (viewType == VIEW_TYPE_EMPTY) {
            //...
        }
    }

    public static class ViewHolder extends ParentViewHolder {
        public ViewHolder(View v) {
            super(v);
        }
    }

    public static class ViewHolderDate extends ViewHolder {

        public ViewHolderDate(View v) {
            super(v);
        }
    }

    public static class ViewHolderEvent extends ViewHolder {

        public ViewHolderEvent(View v) {
            super(v);
        }
    }

}
radu122
fuente
3
@ sfk92fksdf ¿Por qué es propenso a errores? Esta es la forma en que se supone que debe manejar múltiples tipos de vistas en la vista de reciclaje
MSpeed
@billynomates, porque getItemCount()debería ser una línea, pero aquí tenemos una no trivial ifcon alguna lógica oculta. Esta lógica también aparece torpemente getItemViewTypey Dios sabe dónde más
Alexey Andronov
3
No necesita ser una línea. Si tiene varios tipos de vista, esta es la forma de hacerlo.
MSpeed
@ sfk92fksdf ¿Qué quiere decir con lógica oculta? El código está ahí arriba ▲
radu122
1
En mi opinión, esta respuesta debería ser la respuesta aceptada. Realmente es la forma de manejar varios tipos de vistas
Ivo Beckers, el
45

Yo uso ViewSwitcher

<ViewSwitcher
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/switcher"
    >

    <android.support.v7.widget.RecyclerView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

    <TextView android:id="@+id/text_empty"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/list_empty"
        android:gravity="center"
        />

</ViewSwitcher>

en el código verificará el cursor / conjunto de datos y cambiará de vista.

void showItems(Cursor items) {
    if (items.size() > 0) {

        mAdapter.switchCursor(items);

        if (R.id.list == mListSwitcher.getNextView().getId()) {
            mListSwitcher.showNext();
        }
    } else if (R.id.text_empty == mListSwitcher.getNextView().getId()) {
        mListSwitcher.showNext();
    }
}

También puede configurar animaciones si lo desea con un par de líneas de código

mListSwitcher.setInAnimation(slide_in_left);
mListSwitcher.setOutAnimation(slide_out_right);
wnc_21
fuente
Es realmente novedoso
Zhang Xiang el
Solución limpia
Ojonugwa Jude Ochalifu
30

Dado que la respuesta de Kevin no está completa.
Esta es la respuesta más correcta si usa RecyclerAdapter's notifyItemInsertedynotifyItemRemoved para actualizar el conjunto de datos. Vea la versión de Kotlin que otro usuario agregó a continuación.

Java:

mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {

    @Override
    public void onChanged() {
        super.onChanged();
        checkEmpty();
    }

    @Override
    public void onItemRangeInserted(int positionStart, int itemCount) {
        super.onItemRangeInserted(positionStart, itemCount);
        checkEmpty();
    }

    @Override
    public void onItemRangeRemoved(int positionStart, int itemCount) {
        super.onItemRangeRemoved(positionStart, itemCount);
        checkEmpty();
    }

    void checkEmpty() {
        mEmptyView.setVisibility(mAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
    }
});

Kotlin

adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
    override fun onChanged() {
        super.onChanged()
        checkEmpty()
    }

    override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
        super.onItemRangeInserted(positionStart, itemCount)
        checkEmpty()
    }

    override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
        super.onItemRangeRemoved(positionStart, itemCount)
        checkEmpty()
    }

    fun checkEmpty() {
        empty_view.visibility = (if (adapter.itemCount == 0) View.VISIBLE else View.GONE)
    }
})
wonsuc
fuente
2
Esta es una gran solución. Estoy proponiendo una edición que incluirá la versión de Kotlin.
jungledev
Esto parece bueno, pero podría no funcionar si llama a swapAdapter () o incluso a setAdapter () más de una vez.
Glaucus
¡Creo que es la solución más elegante!
entusiasta de Android
Buen trabajo. no olvide ocultar el RecyclerView cuando muestre la etiqueta
MrG
18

RVEmptyObserver

En lugar de utilizar una personalizada RecyclerView, extender una AdapterDataObserveres una solución más simple que permite configurar una personalizada Viewque se muestra cuando no hay elementos en la lista:

Ejemplo de uso:

RVEmptyObserver observer = new RVEmptyObserver(recyclerView, emptyView)
rvAdapter.registerAdapterDataObserver(observer);

Clase:

public class RVEmptyObserver extends RecyclerView.AdapterDataObserver {
    private View emptyView;
    private RecyclerView recyclerView;

    public RVEmptyObserver(RecyclerView rv, View ev) {
        this.recyclerView = rv;
        this.emptyView    = ev;
        checkIfEmpty();
    }

    private void checkIfEmpty() {
        if (emptyView != null && recyclerView.getAdapter() != null) {
            boolean emptyViewVisible = recyclerView.getAdapter().getItemCount() == 0;
            emptyView.setVisibility(emptyViewVisible ? View.VISIBLE : View.GONE);
            recyclerView.setVisibility(emptyViewVisible ? View.GONE : View.VISIBLE);
        }
    }

    public void onChanged() { checkIfEmpty(); }
    public void onItemRangeInserted(int positionStart, int itemCount) { checkIfEmpty(); }
    public void onItemRangeRemoved(int positionStart, int itemCount) { checkIfEmpty(); }
}
Sheharyar
fuente
Creo que va a correr más rápido si usted no llama checkIfEmpty()en onChanged()eonItemRangeInserted()
Geekarist
Estoy de acuerdo (y eso es lo que hice personalmente), pero esto fue solo un punto de partida para las personas que enfrentan este problema.
Sheharyar
9

En el adaptador, getItemViewTypeverifique si el adaptador tiene 0 elementos y devuelve un viewType diferente si es así.

Luego, en su onCreateViewHoldercomprobación, si viewType es el que devolvió anteriormente e infla una vista diferente. En este caso, un archivo de diseño con ese TextView

EDITAR

Si esto todavía no funciona, es posible que desee establecer el tamaño de la vista mediante programación de esta manera:

Point size = new Point();
((WindowManager)itemView.getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getSize(size);

Y luego, cuando infla su llamada de vista:

inflatedView.getLayoutParams().height = size.y;
inflatedView.getLayoutParams().width = size.x;
Pedro Oliveira
fuente
Suena bien. Sin embargo, yo no me meto en onCreateViewHoldercuando mi conjunto de datos es nullo vaciar ya que tengo que volver 0en getItemCount.
JJD
Luego devuelva 1 si es nulo :)
Pedro Oliveira
Funciona un poco Gracias. - Un detalle menor es que no puedo hacer que el elemento de la lista vacía se centre verticalmente en la vista del reciclador. No obstante, la vista de texto permanece en la parte superior de la pantalla que configuré android:layout_gravity="center"y android:layout_height="match_parent"para la vista del reciclador principal.
JJD
Depende del diseño de la fila que está utilizando. Debe emparejar_parent en su altura. Si aún no puede hacerlo funcionar, agregue un oyente de diseño global y configure sus parámetros de diseño para que tengan la misma altura y ancho que la pantalla.
Pedro Oliveira
Todos los contenedores (actividad, fragmento, diseño lineal, vista de reciclador, vista de texto) están configurados en android:layout_height="match_parent". Aunque la fila no se expande a la altura de la pantalla.
JJD
8

Aquí está mi clase para mostrar vista vacía, reintentar vista (cuando falla la API de carga) y cargar el progreso para RecyclerView

public class RecyclerViewEmptyRetryGroup extends RelativeLayout {
    private RecyclerView mRecyclerView;
    private LinearLayout mEmptyView;
    private LinearLayout mRetryView;
    private ProgressBar mProgressBar;
    private OnRetryClick mOnRetryClick;

    public RecyclerViewEmptyRetryGroup(Context context) {
        this(context, null);
    }

    public RecyclerViewEmptyRetryGroup(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RecyclerViewEmptyRetryGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void onViewAdded(View child) {
        super.onViewAdded(child);
        if (child.getId() == R.id.recyclerView) {
            mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
            return;
        }
        if (child.getId() == R.id.layout_empty) {
            mEmptyView = (LinearLayout) findViewById(R.id.layout_empty);
            return;
        }
        if (child.getId() == R.id.layout_retry) {
            mRetryView = (LinearLayout) findViewById(R.id.layout_retry);
            mRetryView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    mRetryView.setVisibility(View.GONE);
                    mOnRetryClick.onRetry();
                }
            });
            return;
        }
        if (child.getId() == R.id.progress_bar) {
            mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
        }
    }

    public void loading() {
        mRetryView.setVisibility(View.GONE);
        mEmptyView.setVisibility(View.GONE);
        mProgressBar.setVisibility(View.VISIBLE);
    }

    public void empty() {
        mEmptyView.setVisibility(View.VISIBLE);
        mRetryView.setVisibility(View.GONE);
        mProgressBar.setVisibility(View.GONE);
    }

    public void retry() {
        mRetryView.setVisibility(View.VISIBLE);
        mEmptyView.setVisibility(View.GONE);
        mProgressBar.setVisibility(View.GONE);
    }

    public void success() {
        mRetryView.setVisibility(View.GONE);
        mEmptyView.setVisibility(View.GONE);
        mProgressBar.setVisibility(View.GONE);
    }

    public RecyclerView getRecyclerView() {
        return mRecyclerView;
    }

    public void setOnRetryClick(OnRetryClick onRetryClick) {
        mOnRetryClick = onRetryClick;
    }

    public interface OnRetryClick {
        void onRetry();
    }
}

actividad_xml

<...RecyclerViewEmptyRetryGroup
        android:id="@+id/recyclerViewEmptyRetryGroup">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"/>

        <LinearLayout
            android:id="@+id/layout_empty">
            ...
        </LinearLayout>

        <LinearLayout
            android:id="@+id/layout_retry">
            ...
        </LinearLayout>

        <ProgressBar
            android:id="@+id/progress_bar"/>

</...RecyclerViewEmptyRetryGroup>

ingrese la descripción de la imagen aquí

La fuente está aquí https://github.com/PhanVanLinh/AndroidRecyclerViewWithLoadingEmptyAndRetry

Phan Van Linh
fuente
7

Utilice AdapterDataObserver en RecyclerView personalizado

Kotlin:

RecyclerViewEnum.kt

enum class RecyclerViewEnum {
    LOADING,
    NORMAL,
    EMPTY_STATE
}

RecyclerViewEmptyLoadingSupport.kt

class RecyclerViewEmptyLoadingSupport : RecyclerView {

    var stateView: RecyclerViewEnum? = RecyclerViewEnum.LOADING
        set(value) {
            field = value
            setState()
        }
    var emptyStateView: View? = null
    var loadingStateView: View? = null


    constructor(context: Context) : super(context) {}

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {}


    private val dataObserver = object : AdapterDataObserver() {
        override fun onChanged() {
            onChangeState()
        }

        override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
            super.onItemRangeRemoved(positionStart, itemCount)
            onChangeState()
        }

        override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
            super.onItemRangeInserted(positionStart, itemCount)
            onChangeState()
        }
    }


    override fun setAdapter(adapter: RecyclerView.Adapter<*>?) {
        super.setAdapter(adapter)
        adapter?.registerAdapterDataObserver(dataObserver)
        dataObserver.onChanged()
    }


    fun onChangeState() {
        if (adapter?.itemCount == 0) {
            emptyStateView?.visibility = View.VISIBLE
            loadingStateView?.visibility = View.GONE
            this@RecyclerViewEmptyLoadingSupport.visibility = View.GONE
        } else {
            emptyStateView?.visibility = View.GONE
            loadingStateView?.visibility = View.GONE
            this@RecyclerViewEmptyLoadingSupport.visibility = View.VISIBLE
        }
    }

    private fun setState() {

        when (this.stateView) {
            RecyclerViewEnum.LOADING -> {
                loadingStateView?.visibility = View.VISIBLE
                this@RecyclerViewEmptyLoadingSupport.visibility = View.GONE
                emptyStateView?.visibility = View.GONE
            }

            RecyclerViewEnum.NORMAL -> {
                loadingStateView?.visibility = View.GONE
                this@RecyclerViewEmptyLoadingSupport.visibility = View.VISIBLE
                emptyStateView?.visibility = View.GONE
            }
            RecyclerViewEnum.EMPTY_STATE -> {
                loadingStateView?.visibility = View.GONE
                this@RecyclerViewEmptyLoadingSupport.visibility = View.GONE
                emptyStateView?.visibility = View.VISIBLE
            }
        }
    }
}

layout.xml

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

    <LinearLayout
        android:id="@+id/emptyView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:id="@+id/emptyLabelTv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="empty" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/loadingView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:gravity="center"
        android:orientation="vertical">

        <ProgressBar
            android:id="@+id/progressBar"
            android:layout_width="45dp"
            android:layout_height="45dp"
            android:layout_gravity="center"
            android:indeterminate="true"
            android:theme="@style/progressBarBlue" />
    </LinearLayout>

    <com.peeyade.components.recyclerView.RecyclerViewEmptyLoadingSupport
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

en actividad use de esta manera:

recyclerView?.apply {
        layoutManager = GridLayoutManager(context, 2)
        emptyStateView = emptyView
        loadingStateView = loadingView
        adapter = adapterGrid
    }

    // you can set LoadingView or emptyView manual
    recyclerView.stateView = RecyclerViewEnum.EMPTY_STATE
    recyclerView.stateView = RecyclerViewEnum.LOADING
Rasoul Miri
fuente
1
Si opta por esa solución, tenga en cuenta que el uso de enumeraciones es insuficiente debido a su mayor tamaño de asignación de memoria. Use Entero o Cadena dependiendo de su contexto con anotaciones StringDefo IntDef
comentarios
2

Agregué una RecyclerViewalternativa ImageViewa RelativeLayout:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/no_active_jobs"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@mipmap/ic_active_jobs" />

    <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

y luego en Adapter:

@Override
public int getItemCount() {
    if (mOrders.size() == 0) {
        mRecyclerView.setVisibility(View.INVISIBLE);
    } else {
        mRecyclerView.setVisibility(View.VISIBLE);
    }
    return mOrders.size();
}
YTerle
fuente
77
cómo llegar mRecyclerViewdentro delAdapter
Basheer AL-MOMANI
2
No es un buen patrón de diseño para vincular el Adaptador a una Actividad específica. Es mejor hacerlo a través de interfaces
ruX
1
Además, esto está causando un sobregiro de diseño, lo que no se recomienda y podría causar algunos problemas de rendimiento. Ver youtube.com/watch?v=T52v50r-JfE para más detalles
Felipe Conde
1

Una forma más es usar addOnChildAttachStateChangeListenerqué maneja las vistas secundarias que aparecen / desaparecen RecyclerView.

recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
            @Override
            public void onChildViewAttachedToWindow(@NonNull View view) {
                forEmptyTextView.setVisibility(View.INVISIBLE);
            }

            @Override
            public void onChildViewDetachedFromWindow(@NonNull View view) {
                forEmptyTextView.setVisibility(View.VISIBLE);
            }
        });
hidd
fuente
0

Solo en caso de que esté trabajando con un FirebaseRecyclerAdapter, esta publicación funciona como un encanto https://stackoverflow.com/a/39058636/6507009

caballero
fuente
77
Si bien este enlace puede responder la pregunta, es mejor incluir aquí las partes esenciales de la respuesta y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia.
Anh Pham