Équivalent de ListView.setEmptyView dans RecyclerView

Dans RecyclerView , je souhaite définir une vue vide pour s'afficher lorsque l'adaptateur est vide. Existe-t-il un équivalent de ListView.setEmptyView() ?

  • Android: setActionView (null) ne supprime pas les problèmes de vue et de largeur sur MenuItem avec ActionView
  • Android - lors de la sortie d'un WebView, l'audio continue de jouer
  • Pourquoi les autorisations sont-elles automatiquement ajoutées à mon AndroidManifest lors de l'inclusion de la bibliothèque Google Play Services
  • Comment désactiver la liste déroulante AutoCompleteTextView de s'afficher?
  • Achats dans l'application Android: devez-vous vérifier l'autorisation com.android.vending.BILLING lors du ciblage d'Android 6?
  • Comment ajouter une image à spinner dans Android
  • 13 Solutions collect form web for “Équivalent de ListView.setEmptyView dans RecyclerView”

    Avec la nouvelle fonctionnalité de liaison de données, vous pouvez également l'obtenir directement dans votre mise en page:

     <TextView android:text="No data to display." android:visibility="@{dataset.size() > 0 ? View.GONE : View.VISIBLE}" /> 

    Dans ce cas, il vous suffit d'ajouter une variable et une importation à la section de données de votre XML:

     <data> <import type="android.view.View"/> <variable name="dataset" type="java.util.List&lt;java.lang.String&gt;" /> </data> 

    Voici une classe similaire à @dragon born, mais plus complète. D'après ce principe .

     public class EmptyRecyclerView extends RecyclerView { private View emptyView; final private AdapterDataObserver observer = new AdapterDataObserver() { @Override public void onChanged() { checkIfEmpty(); } @Override public void onItemRangeInserted(int positionStart, int itemCount) { checkIfEmpty(); } @Override public void onItemRangeRemoved(int positionStart, int itemCount) { checkIfEmpty(); } }; public EmptyRecyclerView(Context context) { super(context); } public EmptyRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public EmptyRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } void checkIfEmpty() { if (emptyView != null && getAdapter() != null) { final boolean emptyViewVisible = getAdapter().getItemCount() == 0; emptyView.setVisibility(emptyViewVisible ? VISIBLE : GONE); setVisibility(emptyViewVisible ? GONE : VISIBLE); } } @Override public void setAdapter(Adapter adapter) { final Adapter oldAdapter = getAdapter(); if (oldAdapter != null) { oldAdapter.unregisterAdapterDataObserver(observer); } super.setAdapter(adapter); if (adapter != null) { adapter.registerAdapterDataObserver(observer); } checkIfEmpty(); } public void setEmptyView(View emptyView) { this.emptyView = emptyView; checkIfEmpty(); } } 

    La solution fournie dans ce lien semble parfaite. Il utilise ViewType pour identifier quand afficher le fichier videView. Pas besoin de créer Custom RecyclerView

    Ajouter un code à partir du lien ci-dessus:

     package com.example.androidsampleproject; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class RecyclerViewActivity extends Activity { RecyclerView recyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recycler_view); recyclerView = (RecyclerView) findViewById(R.id.myList); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(new MyAdapter()); } private class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private List<String> dataList = new ArrayList<String>(); public class EmptyViewHolder extends RecyclerView.ViewHolder { public EmptyViewHolder(View itemView) { super(itemView); } } public class ViewHolder extends RecyclerView.ViewHolder { TextView data; public ViewHolder(View v) { super(v); data = (TextView) v.findViewById(R.id.data_view); } } @Override public int getItemCount() { return dataList.size() > 0 ? dataList.size() : 1; } @Override public int getItemViewType(int position) { if (dataList.size() == 0) { return EMPTY_VIEW; } return super.getItemViewType(position); } @Override public void onBindViewHolder(RecyclerView.ViewHolder vho, final int pos) { if (vho instanceof ViewHolder) { ViewHolder vh = (ViewHolder) vho; String pi = dataList.get(pos); } } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v; if (viewType == EMPTY_VIEW) { v = LayoutInflater.from(parent.getContext()).inflate(R.layout.empty_view, parent, false); EmptyViewHolder evh = new EmptyViewHolder(v); return evh; } v = LayoutInflater.from(parent.getContext()).inflate(R.layout.data_row, parent, false); ViewHolder vh = new ViewHolder(v); return vh; } private static final int EMPTY_VIEW = 10; } } 

    Je préférerais simplement une solution simple comme,

    Avez votre RecyclerView dans FrameLayout ou RelativeLayout avec un TextView ou une autre vue avec l'affichage du message de données vide avec visibilité GONE par défaut, puis dans la classe d'adaptateur, appliquez la logique

    Ici, j'ai un TextView avec message sans données

     @Override public int getItemCount() { textViewNoData.setVisibility(data.size() > 0 ? View.GONE : View.VISIBLE); return data.size(); } 

    Ma version, basée sur https://gist.github.com/adelnizamutdinov/31c8f054d1af4588dc5c

     public class EmptyRecyclerView extends RecyclerView { @Nullable private View emptyView; public EmptyRecyclerView(Context context) { super(context); } public EmptyRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public EmptyRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } private void checkIfEmpty() { if (emptyView != null && getAdapter() != null) { emptyView.setVisibility(getAdapter().getItemCount() > 0 ? GONE : VISIBLE); } } private final AdapterDataObserver observer = new AdapterDataObserver() { @Override public void onChanged() { checkIfEmpty(); } @Override public void onItemRangeInserted(int positionStart, int itemCount) { checkIfEmpty(); } @Override public void onItemRangeRemoved(int positionStart, int itemCount) { checkIfEmpty(); } }; @Override public void setAdapter(@Nullable Adapter adapter) { final Adapter oldAdapter = getAdapter(); if (oldAdapter != null) { oldAdapter.unregisterAdapterDataObserver(observer); } super.setAdapter(adapter); if (adapter != null) { adapter.registerAdapterDataObserver(observer); } checkIfEmpty(); } @Override public void setVisibility(int visibility) { super.setVisibility(visibility); if (null != emptyView && (visibility == GONE || visibility == INVISIBLE)) { emptyView.setVisibility(GONE); } else { checkIfEmpty(); } } public void setEmptyView(@Nullable View emptyView) { this.emptyView = emptyView; checkIfEmpty(); } } 

    Je préférerais mettre en œuvre cette fonctionnalité dans Recycler.Adapter

    Sur votre méthode getItemCount remplacée, injectez des codes de contrôle vides là-bas:

     @Override public int getItemCount() { if(data.size() == 0) listIsEmtpy(); return data.size(); } 

    Si vous souhaitez prendre en charge plus d'états tels que l'état de chargement, indiquez l'état de l'erreur, vous pouvez vérifier https://github.com/rockerhieu/rv-adapter-states . Sinon, le support de la vue vide peut être mis en place facilement en utilisant RecyclerViewAdapterWrapper partir de ( https://github.com/rockerhieu/rv-adapter ). L'avantage principal de cette approche est que vous pouvez facilement supporter la vue vide sans modifier la logique de l'adaptateur existant:

     public class StatesRecyclerViewAdapter extends RecyclerViewAdapterWrapper { private final View vEmptyView; @IntDef({STATE_NORMAL, STATE_EMPTY}) @Retention(RetentionPolicy.SOURCE) public @interface State { } public static final int STATE_NORMAL = 0; public static final int STATE_EMPTY = 2; public static final int TYPE_EMPTY = 1001; @State private int state = STATE_NORMAL; public StatesRecyclerViewAdapter(@NonNull RecyclerView.Adapter wrapped, @Nullable View emptyView) { super(wrapped); this.vEmptyView = emptyView; } @State public int getState() { return state; } public void setState(@State int state) { this.state = state; getWrappedAdapter().notifyDataSetChanged(); notifyDataSetChanged(); } @Override public int getItemCount() { switch (state) { case STATE_EMPTY: return 1; } return super.getItemCount(); } @Override public int getItemViewType(int position) { switch (state) { case STATE_EMPTY: return TYPE_EMPTY; } return super.getItemViewType(position); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_EMPTY: return new SimpleViewHolder(vEmptyView); } return super.onCreateViewHolder(parent, viewType); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (state) { case STATE_EMPTY: onBindEmptyViewHolder(holder, position); break; default: super.onBindViewHolder(holder, position); break; } } public void onBindEmptyViewHolder(RecyclerView.ViewHolder holder, int position) { } public static class SimpleViewHolder extends RecyclerView.ViewHolder { public SimpleViewHolder(View itemView) { super(itemView); } } } 

    Usage:

     Adapter adapter = originalAdapter(); StatesRecyclerViewAdapter statesRecyclerViewAdapter = new StatesRecyclerViewAdapter(adapter, emptyView); rv.setAdapter(endlessRecyclerViewAdapter); // Change the states of the adapter statesRecyclerViewAdapter.setState(StatesRecyclerViewAdapter.STATE_EMPTY); statesRecyclerViewAdapter.setState(StatesRecyclerViewAdapter.STATE_NORMAL); 

    J'ai réparé ceci:
    Créé le layout layout_recyclerview_with_emptytext.xml file.
    Créé EmptyViewRecyclerView.java
    ———

    EmptyViewRecyclerView emptyRecyclerView = (EmptyViewRecyclerView) findViewById (R.id.emptyRecyclerViewLayout);
    EmptyRecyclerView.addAdapter (mPrayerCollectionRecyclerViewAdapter, "Il n'y a pas de prière pour la catégorie sélectionnée");

    Layout_recyclerview_with_emptytext.xml file

      <?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/switcher" > <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" /> <com.ninestars.views.CustomFontTextView android:id="@+id/recyclerViewEmptyTextView" android:layout_width="match_parent" android:layout_height="match_parent" android:text="Empty Text" android:layout_gravity="center" android:gravity="center" android:textStyle="bold" /> </merge> 

    EmptyViewRecyclerView.java

     public class EmptyViewRecyclerView extends ViewSwitcher { private RecyclerView mRecyclerView; private CustomFontTextView mRecyclerViewExptyTextView; public EmptyViewRecyclerView(Context context) { super(context); initView(context); } public EmptyViewRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } private void initView(Context context) { LayoutInflater.from(context).inflate(R.layout.layout_recyclerview_with_emptytext, this, true); mRecyclerViewExptyTextView = (CustomFontTextView) findViewById(R.id.recyclerViewEmptyTextView); mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView); mRecyclerView.setLayoutManager(new LinearLayoutManager(context)); } public void addAdapter(final RecyclerView.Adapter<?> adapter) { mRecyclerView.setAdapter(adapter); adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { @Override public void onChanged() { super.onChanged(); if(adapter.getItemCount() > 0) { if (R.id.recyclerView == getNextView().getId()) { showNext(); } } else { if (R.id.recyclerViewEmptyTextView == getNextView().getId()) { showNext(); } } } }); } public void addAdapter(final RecyclerView.Adapter<?> adapter, String emptyTextMsg) { addAdapter(adapter); setEmptyText(emptyTextMsg); } public RecyclerView getRecyclerView() { return mRecyclerView; } public void setEmptyText(String emptyTextMsg) { mRecyclerViewExptyTextView.setText(emptyTextMsg); } } 
     public class EmptyRecyclerView extends RecyclerView { @Nullable View emptyView; public EmptyRecyclerView(Context context) { super(context); } public EmptyRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public EmptyRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } void checkIfEmpty() { if (emptyView != null) { emptyView.setVisibility(getAdapter().getItemCount() > 0 ? GONE : VISIBLE); } } final @NotNull AdapterDataObserver observer = new AdapterDataObserver() { @Override public void onChanged() { super.onChanged(); checkIfEmpty(); } }; @Override public void setAdapter(@Nullable Adapter adapter) { final Adapter oldAdapter = getAdapter(); if (oldAdapter != null) { oldAdapter.unregisterAdapterDataObserver(observer); } super.setAdapter(adapter); if (adapter != null) { adapter.registerAdapterDataObserver(observer); } } public void setEmptyView(@Nullable View emptyView) { this.emptyView = emptyView; checkIfEmpty(); } } 

    Quelque chose comme ça pourrait aider

    Je pense que c'est plus complet à la fois avec ErrorView et EmptyView https://gist.github.com/henrytao-me/2f7f113fb5f2a59987e7

    Vous pouvez simplement peindre le texte sur RecyclerView lorsqu'il est vide. La sous-classe personnalisée suivante prend en loading offline modes empty , failed , de loading et offline . Pour une compilation réussie, ajoutez la couleur recyclerView_stateText à vos ressources.

     /** * {@code RecyclerView} that supports loading and empty states. */ public final class SupportRecyclerView extends RecyclerView { public enum State { NORMAL, LOADING, EMPTY, FAILED, OFFLINE } public SupportRecyclerView(@NonNull Context context) { super(context); setUp(context); } public SupportRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); setUp(context); } public SupportRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setUp(context); } private Paint textPaint; private Rect textBounds; private PointF textOrigin; private void setUp(Context c) { textPaint = new Paint(); textPaint.setAntiAlias(true); textPaint.setColor(ContextCompat.getColor(c, R.color.recyclerView_stateText)); textBounds = new Rect(); textOrigin = new PointF(); } private State state; public State state() { return state; } public void setState(State newState) { state = newState; calculateLayout(getWidth(), getHeight()); invalidate(); } private String loadingText = "Loading..."; public void setLoadingText(@StringRes int resId) { loadingText = getResources().getString(resId); } private String emptyText = "Empty"; public void setEmptyText(@StringRes int resId) { emptyText = getResources().getString(resId); } private String failedText = "Failed"; public void setFailedText(@StringRes int resId) { failedText = getResources().getString(resId); } private String offlineText = "Offline"; public void setOfflineText(@StringRes int resId) { offlineText = getResources().getString(resId); } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); String s = stringForCurrentState(); if (s == null) return; canvas.drawText(s, textOrigin.x, textOrigin.y, textPaint); } private void calculateLayout(int w, int h) { String s = stringForCurrentState(); if (s == null) return; textPaint.setTextSize(.1f * w); textPaint.getTextBounds(s, 0, s.length(), textBounds); textOrigin.set( w / 2f - textBounds.width() / 2f - textBounds.left, h / 2f - textBounds.height() / 2f - textBounds.top); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); calculateLayout(w, h); } private String stringForCurrentState() { if (state == State.EMPTY) return emptyText; else if (state == State.LOADING) return loadingText; else if (state == State.FAILED) return failedText; else if (state == State.OFFLINE) return offlineText; else return null; } } 

    De mon point de vue, la manière la plus simple de faire une vue vide est de créer une nouvelle RecyclerView vide avec la disposition que vous souhaitez gonfler en arrière-plan. Et cet adaptateur vide est réglé lorsque vous vérifiez la taille de votre jeu de données.

    Essayez RVEmptyObserver :

    C'est une implémentation d'un AdapterDataObserver qui vous permet de définir simplement une View comme la disposition vide par défaut pour votre RecylerView . De cette façon, au lieu d'utiliser un RecyclerView personnalisé et de rendre votre vie plus difficile, vous pouvez facilement l'utiliser avec votre code existant:


    Exemple d'utilisation:

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

    Vous pouvez voir le code et l' utilisation d'exemple dans une application actuelle ici.


    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(); } } 
    coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.