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.
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);
}
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));
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);
}
}
}
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);
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)
}
})
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(); }
}
Ü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;
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>
Die Quelle ist hier https://github.com/PhanVanLinh/AndroidRecyclerViewWithLoadingEmptyAndRetry
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
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();
}
Nur falls Sie mit einem FirebaseRecyclerAdapter arbeiten, funktioniert dieser Beitrag wie ein Zauber https://stackoverflow.com/a/39058636/6507009