Comment afficher une vue vide avec une RecyclerView?

271

J'ai l'habitude de mettre une vue spéciale à l'intérieur du fichier de mise en page comme décrit dans la ListActivitydocumentation à afficher lorsqu'il n'y a pas de données . Cette vue a l'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" />

Je me demande comment cela peut être fait avec le nouveau RecyclerView?

JJD
la source
2
Vous pouvez utiliser github.com/rockerhieu/rv-adapter-states , il prend en charge non seulement la vue vide mais également la vue de chargement et la vue d'erreur. Et vous pouvez l'utiliser sans changer la logique de l'adaptateur existant.
Hieu Rocker
20
Ce n'est que fascinant qu'il ne semble pas y avoir de setEmptyView()méthode simple contre un RecyclerView...
Subby
Voici ma réponse, veuillez vérifier ce lien stackoverflow.com/a/58411351/5449220
Rakesh Verma
@Subby, d'accord, mais setEmptyView()avait également un inconvénient. Lors du chargement des données, nous ne voulions pas afficher la vue vide ListView, mais c'était le cas. Nous avons donc dû implémenter une logique. Actuellement, j'utilise stackoverflow.com/a/48049142/2914140 .
CoolMind

Réponses:

306

Sur la même mise en page où est défini le RecyclerView, ajoutez le 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" />

Lors du onCreateou du rappel approprié, vous vérifiez si l'ensemble de données qui alimente votre RecyclerViewest vide. Si l'ensemble de données est vide, l' RecyclerViewest également. Dans ce cas, le message apparaît à l'écran. Sinon, changez sa visibilité:

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
la source
11
Cela ne fonctionne pas pour moi car la disposition de la vue recycleur est gonflée dans le fragment alors que la décision d'afficher une disposition d'élément normale ou une disposition sans élément est prise dans l'adaptateur.
JJD
1
@JJD lors de l'utilisation d'un fragment, la même chose s'applique. Lorsque vous gonflez votre vue de fragment, vous avez la vue de recyclage, puis une autre disposition qui serait utilisée pour votre vue vide. Habituellement, dans mes fragments, j'ai les vues suivantes: 1) vue d'ensemble du recyclage, 2) vue vide et 3) vue de la barre de progression. Je passe généralement l'adaptateur quelle que soit la liste, mais en fonction de la taille de la liste, je vais masquer la vue de recyclage et afficher le vide ou vice versa. Si une vue de recyclage a une liste vide, elle n'en fait rien. Vous voyez juste une vue vide.
Ray Hunter
1
@stackex La vérification doit être dans le rappel onCreateView du fragment ou onResume of Activity. De cette façon, la vérification sera effectuée immédiatement avant l'affichage de l'écran à l'utilisateur et fonctionnera pour les deux, augmentant ou diminuant la quantité de lignes dans l'ensemble de données.
slellis
2
@Zapnologica Vous pouvez le faire dans l'autre sens: utilisez un Eventbus (tel que Greenrobots Eventbus ou Otto), puis placez l'adaptateur sur le Eventbus lorsque l'ensemble de données change. Dans le fragment, il vous suffit de créer une méthode dont les paramètres correspondent à ce que l'adaptateur transmet à la méthode Eventbus.post, puis de modifier la disposition en conséquence. Une approche plus simple mais également plus couplée consiste à créer une interface de rappel dans l'adaptateur, et lors de la création de l'adaptateur, le fragment doit l'implémenter.
AgentKnopf
2
Dans la mise en page, j'obtiens plusieurs balises racine. À quoi ressemble votre fichier de mise en page complet?
powder366
192

Pour mes projets j'ai réalisé cette solution ( RecyclerViewavec setEmptyViewméthode):

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

Et vous devez l'utiliser à la place de la 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"
    />

et

RecyclerViewEmptySupport list = 
    (RecyclerViewEmptySupport)rootView.findViewById(R.id.list1);
list.setLayoutManager(new LinearLayoutManager(context));
list.setEmptyView(rootView.findViewById(R.id.list_empty));
maff91
la source
2
Avez-vous pris ce code de cette réponse ou d'ici ?
Sufian
@Sufian Non, je n'ai pas vu cette réponse, j'ai trouvé la même chose. Mais ce code semble définitivement plus joli que le mien :)
maff91
2
J'ai essayé de combiner cela avec le FirebaseRecyclerAdapter, cela n'a pas fonctionné. En effet, FirebaseRecyclerAdapter n'appelle pas onChange (de AdapterDataObserver), mais appelle à la place les méthodes onItem *. Pour le faire fonctionner, ajoutez: `Override public void onItemRangeRemoved (int positionStart, int itemCount) {// la vérification} Override public void onItemRangeMoved (int fromPosition, int toPosition, int itemCount) {// la vérification} // etc ..`
FrankkieNL
1
Pourquoi vérifiez-vous si l'adaptateur est nul dans l'observateur? si l'adaptateur est nul, l'observateur ne doit jamais être appelé.
Stimsoni
16
ugh, je dois dire que c'est juste Google BS classique. Je dois implémenter cela juste pour ajouter une vue vide? Il devrait être inclus dans leur SDK cr @ psh1t! Pour l'amour de Dieu!
Neon Warge
62

Voici une solution utilisant uniquement un adaptateur personnalisé avec un type de vue différent pour la situation vide.

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
la source
3
@ sfk92fksdf Pourquoi est-il sujet aux erreurs? C'est ainsi que vous êtes censé gérer plusieurs types de vues dans recyclerview
MSpeed
@billynomates, car getItemCount()devrait être un oneliner mais ici nous avons un non trivial ifavec une logique cachée. Cette logique apparaît également maladroitement getItemViewTypeet Dieu sait où d'autre
Alexey Andronov
3
Il n'est pas nécessaire que ce soit une seule ligne. Si vous avez plusieurs types de vue, c'est la façon de procéder.
MSpeed
@ sfk92fksdf Qu'entendez-vous par logique cachée? Le code est là haut ▲
radu122
1
à mon avis, cette réponse devrait être la réponse acceptée. C'est vraiment la façon de gérer plusieurs types de vues
Ivo Beckers
45

J'utilise 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>

dans le code, vous allez vérifier le curseur / jeu de données et changer de vue.

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

Vous pouvez également définir des animations si vous le souhaitez avec quelques lignes de code

mListSwitcher.setInAnimation(slide_in_left);
mListSwitcher.setOutAnimation(slide_out_right);
wnc_21
la source
C'est vraiment nouveau
Zhang Xiang
Solution propre.
Ojonugwa Jude Ochalifu
30

Puisque la réponse de Kevin n'est pas complète.
Il s'agit d'une réponse plus correcte si vous utilisez RecyclerAdapterla commande notifyItemInsertedet notifyItemRemovedpour mettre à jour l'ensemble de données. Voir la version Kotlin ajoutée par un autre utilisateur ci-dessous.

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
la source
2
C'est une excellente solution. Je lui propose une modification qui inclura la version kotlin.
jungledev
Cela semble bien mais peut ne pas fonctionner si vous appelez swapAdapter () ou même setAdapter () plus d'une fois.
Glaucus
Je pense que c'est la solution la plus élégante!
passionné d'androïde
Bon travail. n'oubliez pas de masquer le RecyclerView lorsque vous montrez l'étiquette
MrG
18

RVEmptyObserver

Au lieu d'utiliser une personnalisation RecyclerView, l'extension d'une AdapterDataObserverest une solution plus simple qui permet de définir uneView qui s'affiche lorsqu'il n'y a aucun élément dans la liste:

Exemple d'utilisation:

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
la source
Je crois qu'il va courir plus vite si vous n'appelez pas checkIfEmpty()dans onChanged()etonItemRangeInserted()
Geekarist
Je suis d'accord (et c'est ce que j'ai fait personnellement), mais c'était juste destiné à être un point de départ pour les personnes confrontées à ce problème.
Sheharyar
9

Lors de la getItemViewTypevérification de votre adaptateur, si l'adaptateur a 0 élément et si tel est le cas, renvoyez un viewType différent.

Ensuite, onCreateViewHoldervérifiez si le viewType est celui que vous avez retourné plus tôt et gonflez une vue différente. Dans ce cas, un fichier de mise en page avec ce TextView

ÉDITER

Si cela ne fonctionne toujours pas, vous pouvez définir la taille de la vue par programme comme ceci:

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

Et puis, lorsque vous gonflez votre appel de vue:

inflatedView.getLayoutParams().height = size.y;
inflatedView.getLayoutParams().width = size.x;
Pedro Oliveira
la source
Ça m'a l'air bien. Cependant , je ne suis pas dans onCreateViewHolderquand mon jeu de données est nullou vide depuis que je dois retourner 0dans getItemCount.
JJD
Puis retournez 1 s'il est nul :)
Pedro Oliveira
Fonctionne un peu. Je vous remercie. - Un détail mineur est que je ne parviens pas à centrer verticalement l' élément de liste vide dans la vue du recycleur. La vue texte reste en haut de l'écran, mais j'ai défini android:layout_gravity="center"et android:layout_height="match_parent"pour la vue parent recycleur.
JJD
Cela dépend de la disposition de la ligne que vous utilisez. Il doit correspondre_parent à sa hauteur. Si vous ne pouvez toujours pas le faire fonctionner, ajoutez un écouteur de mise en page globale et définissez ses paramètres de mise en page pour qu'ils aient la même hauteur et la même largeur que l'écran.
Pedro Oliveira
Tous les conteneurs (activité, fragment, disposition linéaire, vue recycleur, vue texte) sont définis sur android:layout_height="match_parent". Bien que la ligne ne s'étende pas à la hauteur de l'écran.
JJD
8

Voici ma classe pour afficher la vue vide, réessayer la vue (lorsque le chargement de l'api a échoué) et la progression du chargement pour 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>

entrez la description de l'image ici

La source est ici https://github.com/PhanVanLinh/AndroidRecyclerViewWithLoadingEmptyAndRetry

Phan Van Linh
la source
7

Utilisez AdapterDataObserver dans RecyclerView personnalisé

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 activité utiliser de cette façon:

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
la source
1
Si vous optez pour cette solution, faites attention à ce que l'utilisation d'énumérations soit insuffisante en raison de l'augmentation de la taille de l'allocation de mémoire. Utilisez Entier ou chaîne en fonction de votre contexte avec appropriées StringDefou IntDefannotations
Andrii Artamonov
2

J'ai ajouté RecyclerViewet alternative ImageViewau 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>

puis dans Adapter:

@Override
public int getItemCount() {
    if (mOrders.size() == 0) {
        mRecyclerView.setVisibility(View.INVISIBLE);
    } else {
        mRecyclerView.setVisibility(View.VISIBLE);
    }
    return mOrders.size();
}
YTerle
la source
7
comment arriver mRecyclerViewà l'intérieur duAdapter
Basheer AL-MOMANI
2
Ce n'est pas un bon modèle de conception pour lier l'adaptateur à une activité spécifique. Il vaut mieux le faire via des interfaces
ruX
1
Cela provoque également un dépassement de la mise en page, ce qui n'est pas recommandé et cela pourrait entraîner des problèmes de performances. Voir youtube.com/watch?v=T52v50r-JfE pour plus de détails
Felipe Conde
1

Une autre façon consiste à utiliser les addOnChildAttachStateChangeListenerpoignées des vues enfant apparaissant / disparaissant dans 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);
            }
        });
cacher
la source
0

Au cas où vous travaillez avec un FirebaseRecyclerAdapter, ce message fonctionne comme un charme https://stackoverflow.com/a/39058636/6507009

chevalier
la source
7
Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien de référence. Les réponses de lien uniquement peuvent devenir invalides si la page liée change.
Anh Pham