Como mostrar uma exibição vazia com um RecyclerView?

271

Estou acostumado a colocar uma exibição especial dentro do arquivo de layout, conforme descrito na ListActivitydocumentação, a ser exibida quando não houver dados . Essa visualização tem o ID "android:id/empty".

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

Gostaria de saber como isso pode ser feito com o novo RecyclerView?

JJD
fonte
2
Você pode usar o github.com/rockerhieu/rv-adapter-states , ele suporta não apenas a visualização vazia, mas também o carregamento da visualização e da visualização de erros. E você pode usá-lo sem alterar a lógica do adaptador existente.
Hieu Rocker
20
Não é nada, mas fascinante que não parece ser um simples setEmptyView()método contra um RecyclerView...
Subby
Aqui está a minha resposta, por favor, verifique este link stackoverflow.com/a/58411351/5449220
Rakesh Verma 16/10/19
@ Subby, concordo, mas setEmptyView()também teve desvantagem. Ao carregar dados, não queríamos mostrar a exibição vazia ListView, mas foi o que fizemos. Então, tivemos que implementar alguma lógica. Atualmente, uso stackoverflow.com/a/48049142/2914140 .
CoolMind 15/11

Respostas:

306

No mesmo layout em que está definido RecyclerView, adicione o TextView:

<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" />

No onCreateretorno de chamada ou apropriado, você verifica se o conjunto de dados que alimenta o seu RecyclerViewestá vazio. Se o conjunto de dados estiver vazio, RecyclerViewtambém estará vazio. Nesse caso, a mensagem aparece na tela. Caso contrário, altere sua visibilidade:

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
fonte
11
Isso não funciona para mim porque o layout da exibição do reciclador é inflado no fragmento, enquanto a decisão de mostrar um layout normal de item ou um layout sem itens é tomada no adaptador.
JJD
1
@JJD ao usar um fragmento, a mesma coisa se aplica. Ao inflar a visualização de fragmento, você tem a visualização de reciclagem e, em seguida, outro layout que seria usado para a visualização vazia. Normalmente, em meus fragmentos, terei as seguintes visualizações: 1) visão de reciclagem, 2) visão vazia e 3) visão da barra de progresso. Normalmente, passo o adaptador independentemente da lista, mas com base no tamanho da lista, ocultarei a recyclerview e mostrarei o vazio ou vice-versa. Se uma revisão de reciclagem tiver uma lista vazia, ela não fará nada com ela. Você acabou de ver uma visão vazia.
Raio do caçador
1
@stackex A verificação deve estar no retorno de chamada onCreateView do fragmento ou no resumo da atividade. Dessa forma, a verificação será feita imediatamente antes da exibição da tela para o usuário e funcionará para ambos, aumentando ou diminuindo a quantidade de linhas no conjunto de dados.
Slellis
2
@Zapnologica Você pode fazer o contrário: use um Eventbus (como greenrobots Eventbus ou Otto) e depois coloque o Adaptador no eventbus quando o conjunto de dados mudar. No fragmento, tudo o que você faz é criar um método cujos parâmetros correspondam ao que o Adaptador está passando no método Eventbus.post e, em seguida, alterar o layout de acordo. Uma abordagem mais simples, mas também mais acoplada, é criar uma interface de retorno de chamada no adaptador e, ao criar o adaptador, o fragmento a implementará.
precisa saber é o seguinte
2
No layout, recebo várias tags raiz. Como é o seu arquivo de layout completo?
powder366
192

Para meus projetos, fiz esta solução ( RecyclerViewcom 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;
    }
}

E você deve usá-lo em vez da RecyclerViewclasse:

<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"
    />

e

RecyclerViewEmptySupport list = 
    (RecyclerViewEmptySupport)rootView.findViewById(R.id.list1);
list.setLayoutManager(new LinearLayoutManager(context));
list.setEmptyView(rootView.findViewById(R.id.list_empty));
maff91
fonte
2
Você pegou esse código nesta resposta ou aqui ?
Sufian
@ Suufian Não, eu não vi essa resposta, apenas achei da mesma maneira. Mas esse código definitivamente parece mais bonita do que a minha :)
maff91
2
Eu tentei combinar isso com o FirebaseRecyclerAdapter, não funcionou. Isso ocorre porque o FirebaseRecyclerAdapter não chama o onChange (do AdapterDataObserver), mas chama o onItem * -methods. Para fazê-lo funcionar, adicione: `Substitua public void onItemRangeRemoved (int positionStart, int itemCount) {// a verificação} Substitua public void onItemRangeMoved (int fromPosition, int toPosition, int itemCount) {// a verificação} // etc ..`
FrankkieNL
1
Por que você verifica se o adaptador é nulo no observador? se o adaptador for nulo, o observador nunca deve ser chamado.
Stimsoni 27/07/16
16
ugh, devo dizer que este é apenas o clássico Google BS. Eu tenho que implementar isso apenas para adicionar uma visão vazia? Ele deve ser incluído no SDK cr @ psh1t! Pelo amor de Deus!
Neon Warge
62

Aqui está uma solução usando apenas um adaptador personalizado com um tipo de exibição diferente para a situação vazia.

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
fonte
3
@ sfk92fksdf Por que é propenso a erros? Esta é a maneira que é suposto para lidar com vários tipos de vista em recyclerview
MSpeed
@billynomates, porque getItemCount()deve ser um oneliner, mas aqui temos um não trivial ifcom alguma lógica oculta. Essa lógica também aparece desajeitadamente em getItemViewTypee deus sabe onde mais
Alexey Andronov
3
Não precisa ser uma linha. Se você possui vários tipos de visualização, é esse o caminho.
MSpeed
@ sfk92fksdf O que você quer dizer com lógica oculta? O código está lá em cima ▲
radu122 17/17/17
1
na minha opinião, essa resposta deve ser a resposta aceita. É realmente a maneira de lidar com tipos de vista mutliple
Ivo Beckers
45

Eu uso o 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>

no código, você verificará o cursor / conjunto de dados e alternará as visualizações.

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();
    }
}

Além disso, você pode definir animações, se desejar, com algumas linhas de código

mListSwitcher.setInAnimation(slide_in_left);
mListSwitcher.setOutAnimation(slide_out_right);
wnc_21
fonte
É realmente uma novela
Zhang Xiang
Solução limpa.
Ojonugwa Jude Ochalifu
30

Como a resposta de Kevin não está completa.
Essa é a resposta mais correta se você usar RecyclerAdapter's notifyItemInsertede notifyItemRemovedatualizar o conjunto de dados. Veja a versão Kotlin de outro usuário adicionado abaixo.

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
fonte
2
Esta é uma otima soluçao. Estou propondo uma edição que incluirá a versão kotlin.
jungledev
Isso parece bom, mas pode não funcionar se você chamar swapAdapter () ou setAdapter () mais de uma vez.
Glaucus
Eu acho que é a solução mais elegante!
entusiasta do Android
Ótimo trabalho. não esqueça de ocultar o RecyclerView ao exibir o rótulo
MrG
18

RVEmptyObserver

Em vez de usar um personalizado RecyclerView, estender um AdapterDataObserveré uma solução mais simples que permite definir um personalizado Viewque é exibido quando não há itens na lista:

Exemplo de uso:

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

Classe:

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
fonte
Eu acredito que ele vai correr mais rápido se você não chamar checkIfEmpty()no onChanged()eonItemRangeInserted()
Geekarist
Concordo (e foi o que fiz pessoalmente), mas isso foi apenas o ponto de partida para as pessoas que enfrentam esse problema.
Sheharyar # 24/17
9

No adaptador, getItemViewTypeverifique se o adaptador possui 0 elementos e, se houver, retorne um viewType diferente.

Em seguida, onCreateViewHolderverifique se o viewType é o que você retornou anteriormente e inflate uma visualização diferente. Nesse caso, um arquivo de layout com esse TextView

EDITAR

Se isso ainda não estiver funcionando, convém definir o tamanho da exibição programaticamente da seguinte maneira:

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

E então, quando você aumenta sua chamada de visualização:

inflatedView.getLayoutParams().height = size.y;
inflatedView.getLayoutParams().width = size.x;
Pedro Oliveira
fonte
Parece bom. No entanto, eu não entrar em onCreateViewHolderquando o meu conjunto de dados é nullou esvaziar uma vez eu tenho que voltar 0no getItemCount.
JJD
Em seguida, retornar 1 se ele é nulo :)
Pedro Oliveira
Funciona um pouco. Obrigado. - Pequenos detalhes é que não consigo obter o item da lista vazio centralizado verticalmente na exibição do reciclador. A exibição de texto permanece na parte superior da tela, no entanto, eu defini android:layout_gravity="center"e android:layout_height="match_parent"para a exibição de reciclador pai.
JJD 6/15
Depende do layout da linha que você está usando. Ele deve corresponder ao pai em sua altura. Se você ainda não conseguir fazê-lo funcionar, adicione um ouvinte de layout global e defina seus parâmetros de layout para ter a mesma altura e largura da tela.
Pedro Oliveira
Todos os contêineres (atividade, fragmento, layout linear, exibição de reciclador, exibição de texto) estão definidos como android:layout_height="match_parent". Embora a linha não se expanda para a altura da tela.
JJD 6/02
8

Aqui está minha turma para mostrar a exibição vazia, tentar novamente (quando a API de carregamento falhou) e carregar o progresso de 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();
    }
}

activity_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>

insira a descrição da imagem aqui

A fonte está aqui https://github.com/PhanVanLinh/AndroidRecyclerViewWithLoadingEmptyAndRetry

Phan Van Linh
fonte
7

Use AdapterDataObserver no 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>

em atividade, use desta maneira:

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
fonte
1
Se você optar por essa solução, preste atenção que o uso de enumerações é insuficiente devido ao aumento no tamanho da alocação de memória. Use integer ou string, dependendo do contexto, com apropriadas StringDefou IntDefanotações
Andrii Artamonov
2

Eu adicionei RecyclerViewe alternativa ImageViewao 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>

e depois em Adapter:

@Override
public int getItemCount() {
    if (mOrders.size() == 0) {
        mRecyclerView.setVisibility(View.INVISIBLE);
    } else {
        mRecyclerView.setVisibility(View.VISIBLE);
    }
    return mOrders.size();
}
YTerle
fonte
7
como chegar mRecyclerViewdentro deAdapter
Basheer AL-MOMANI 6/16
2
Não é um bom padrão de design vincular o Adaptador a Atividade específica. É melhor fazer isso por meio de interfaces
Rux
1
Isso também está causando um excesso de layout, o que não é recomendado e pode causar alguns problemas de desempenho. Veja youtube.com/watch?v=T52v50r-JfE para obter mais detalhes
Felipe Conde
1

Mais uma maneira é usar o addOnChildAttachStateChangeListenerque lida com as exibições filho que aparecem / desaparecem no 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
fonte
0

Apenas se você estiver trabalhando com um FirebaseRecyclerAdapter, este post funciona como um encanto https://stackoverflow.com/a/39058636/6507009

knightcube
fonte
7
Embora esse link possa responder à pergunta, é melhor incluir aqui as partes essenciais da resposta e fornecer o link para referência. As respostas somente para links podem se tornar inválidas se a página vinculada for alterada.
Anh Pham