it-swarm.com.de

Wie zeige ich eine leere Ansicht mit einem RecyclerView an?

Ich werde verwendet, um eine spezielle Ansicht in die Layoutdatei einzufügen, wie beschrieben in der Dokumentation zu ListActivity angezeigt werden soll , wenn keine Daten vorhanden sind . Diese Ansicht hat die 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" />

Ich frage mich, wie das mit dem neuen RecyclerView gemacht werden kann.

235
JJD

Fügen Sie im selben Layout, in dem das RecyclerView definiert ist, das TextView hinzu:

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

Am onCreate oder dem entsprechenden Rückruf prüfen Sie, ob der Datensatz, der Ihr RecyclerView füttert, leer ist. Wenn der Datensatz leer ist, ist auch RecyclerView leer. In diesem Fall wird die Meldung auf dem Bildschirm angezeigt. Wenn nicht, ändern Sie die Sichtbarkeit:

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);
}
271
slellis

Für meine Projekte habe ich diese Lösung erstellt (RecyclerView mit setEmptyView Methode):

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

Und Sie sollten es anstelle der Klasse RecyclerView verwenden:

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

und

RecyclerViewEmptySupport list = 
    (RecyclerViewEmptySupport)rootView.findViewById(R.id.list1);
list.setLayoutManager(new LinearLayoutManager(context));
list.setEmptyView(rootView.findViewById(R.id.list_empty));
189
maff91

Hier ist eine Lösung, die nur einen benutzerdefinierten Adapter mit einem anderen Ansichtstyp für die leere Situation verwendet.

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

}
59
radu122

Ich benutze 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>

im Code überprüfen Sie den Cursor/Datensatz und wechseln die Ansicht.

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

Sie können auch Animationen einstellen, wenn Sie dies mit ein paar Codezeilen wünschen

mListSwitcher.setInAnimation(slide_in_left);
mListSwitcher.setOutAnimation(slide_out_right);
42
wnc_21

Da ist Kevins Antwort nicht vollständig.
Dies ist die korrektere Antwort, wenn Sie zum Aktualisieren des Datensatzes RecyclerAdapter und notifyItemInserted von notifyItemRemoved verwenden. Siehe die Kotlin-Version, die ein anderer Benutzer unten hinzugefügt hat.

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)
    }
})
20
wonsuc

RVEmptyObserver

Anstatt ein benutzerdefiniertes RecyclerView zu verwenden, ist das Erweitern eines AdapterDataObserver eine einfachere Lösung, mit der ein benutzerdefiniertes View festgelegt werden kann, das angezeigt wird, wenn sich keine Elemente in der Liste befinden:

Beispielverwendung:

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

Klasse:

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

Überprüfen Sie auf dem getItemViewType Ihres Adapters, ob der Adapter 0 Elemente enthält, und geben Sie gegebenenfalls einen anderen viewType zurück.

Überprüfen Sie dann auf Ihrem onCreateViewHolder, ob der viewType derjenige ist, den Sie zuvor zurückgegeben haben, und blähen Sie eine andere Ansicht auf. In diesem Fall eine Layoutdatei mit diesem TextView

EDIT

Wenn dies immer noch nicht funktioniert, können Sie die Größe der Ansicht wie folgt programmgesteuert festlegen:

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

Und dann, wenn Sie Ihren Sichtaufruf aufblasen:

inflatedView.getLayoutParams().height = size.y;
inflatedView.getLayoutParams().width = size.x;
9
Pedro Oliveira

Hier ist meine Klasse für die Anzeige der leeren Ansicht, die Wiederholungsansicht (wenn das Laden der API fehlgeschlagen ist) und den Ladevorgang für 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>

enter image description here

Die Quelle ist hier https://github.com/PhanVanLinh/AndroidRecyclerViewWithLoadingEmptyAndRetry

7
Phan Van Linh

Verwenden Sie AdapterDataObserver in benutzerdefiniertem RecyclerView

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
            [email protected] = View.GONE
        } else {
            emptyStateView?.visibility = View.GONE
            loadingStateView?.visibility = View.GONE
            [email protected] = View.VISIBLE
        }
    }

    private fun setState() {

        when (this.stateView) {
            RecyclerViewEnum.LOADING -> {
                loadingStateView?.visibility = View.VISIBLE
                [email protected] = View.GONE
                emptyStateView?.visibility = View.GONE
            }

            RecyclerViewEnum.NORMAL -> {
                loadingStateView?.visibility = View.GONE
                [email protected] = View.VISIBLE
                emptyStateView?.visibility = View.GONE
            }
            RecyclerViewEnum.EMPTY_STATE -> {
                loadingStateView?.visibility = View.GONE
                [email protected] = 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>

in der Aktivität benutze diesen Weg:

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
5
Rasoul Miri

Ich habe RecyclerView und alternative ImageView zu RelativeLayout hinzugefügt:

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

und dann in Adapter:

@Override
public int getItemCount() {
    if (mOrders.size() == 0) {
        mRecyclerView.setVisibility(View.INVISIBLE);
    } else {
        mRecyclerView.setVisibility(View.VISIBLE);
    }
    return mOrders.size();
}
2
YTerle

Nur falls Sie mit einem FirebaseRecyclerAdapter arbeiten, funktioniert dieser Beitrag wie ein Zauber https://stackoverflow.com/a/39058636/6507009

1
knightcube