Di RecyclerView
, saya ingin mengatur tampilan kosong untuk ditampilkan saat adaptor kosong. Apakah ada yang setara dengan ListView.setEmptyView()
?
android
android-recyclerview
Manish Mulimani
sumber
sumber
Jawaban:
Dengan fitur data binding baru, Anda juga dapat melakukannya di layout Anda secara langsung:
<TextView android:text="No data to display." android:visibility="@{dataset.size() > 0 ? View.GONE : View.VISIBLE}" />
Dalam hal ini Anda hanya perlu menambahkan variabel dan mengimpor ke bagian data XML Anda:
<data> <import type="android.view.View"/> <variable name="dataset" type="java.util.List<java.lang.String>" /> </data>
sumber
Adapter
alih - alih kumpulan data dan menggunakangetItemCount()
atau membungkus semuanya dalam aViewModel
dan setandroid:visibility
toviewModel.getEmptyViewVisibility()
.Ini kelas yang mirip dengan @dragon born, tetapi lebih lengkap. Berdasarkan inti ini .
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(); } }
sumber
setEmptyView
metode, yang bisa Anda panggil kapan pun Anda ingin mendefinisikan tampilan kosong. LihatListView.setEmptyView
dokumentasinya jika tidak jelas, idenya sama.Solusi yang diberikan di tautan ini tampaknya sempurna. Ini menggunakan viewType untuk mengidentifikasi kapan menampilkan emptyView. Tidak perlu membuat RecyclerView khusus
Menambahkan kode dari tautan di atas:
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; } }
sumber
Saya lebih suka solusi sederhana seperti,
memiliki RecyclerView Anda di dalam FrameLayout atau RelativeLayout dengan TextView atau tampilan lain dengan menampilkan pesan data kosong dengan visibilitas GONE secara default dan kemudian di kelas adaptor, terapkan logikanya
Di sini, saya memiliki satu TextView dengan pesan tanpa data
@Override public int getItemCount() { textViewNoData.setVisibility(data.size() > 0 ? View.GONE : View.VISIBLE); return data.size(); }
sumber
Coba
RVEmptyObserver
:Ini adalah implementasi
AdapterDataObserver
yang memungkinkan Anda menyetel aView
sebagai tata letak kosong default untuk fileRecylerView
. Dengan cara ini, alih-alih menggunakan kebiasaanRecyclerView
dan membuat hidup Anda lebih sulit, Anda dapat dengan mudah menggunakannya dengan kode yang ada:Contoh Penggunaan:
RVEmptyObserver observer = new RVEmptyObserver(recyclerView, emptyView) rvAdapter.registerAdapterDataObserver(observer);
Anda dapat melihat kode dan contoh penggunaan dalam aplikasi sebenarnya di sini.
Kelas:
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(); } }
sumber
Versi saya, berdasarkan 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(); } }
sumber
setVisibility
juga.Saya lebih suka mengimplementasikan fungsi ini di Recycler.Adapter
Pada metode getItemCount yang diganti, masukkan kode cek kosong di sana:
@Override public int getItemCount() { if(data.size() == 0) listIsEmtpy(); return data.size(); }
sumber
setVisibility()
dipanggil. Tentu Anda bisa menambahkan beberapa bendera sebagai kompensasi tetapi saat itulah semakin kompleks.Jika Anda ingin mendukung lebih banyak status seperti status pemuatan, status kesalahan maka Anda dapat melakukan checkout https://github.com/rockerhieu/rv-adapter-states . Jika tidak, mendukung tampilan kosong dapat diimplementasikan dengan mudah menggunakan
RecyclerViewAdapterWrapper
from ( https://github.com/rockerhieu/rv-adapter ). Keuntungan utama dari pendekatan ini adalah Anda dapat dengan mudah mendukung tampilan kosong tanpa mengubah logika adaptor yang ada: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); } } }
Pemakaian:
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);
sumber
Saya telah memperbaiki ini:
Membuat file layout layout_recyclerview_with_emptytext.xml.
Dibuat EmptyViewRecyclerView.java
---------
EmptyViewRecyclerView emptyRecyclerView = (EmptyViewRecyclerView) findViewById (R.id.emptyRecyclerViewLayout);
emptyRecyclerView.addAdapter (mPrayerCollectionRecyclerViewAdapter, "Tidak ada doa untuk kategori yang dipilih.");
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); } }
sumber
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(); } }
sesuatu seperti ini mungkin bisa membantu
sumber
RecyclerView
kapanemptyView
terlihat (dan sebaliknya). Anda juga harus panggilancheckIfEmpty()
padaonItemRangeInserted()
danonItemRangeRemoved()
. Oh, dan Anda bisa mengutip sumber Anda: gist.github.com/adelnizamutdinov/31c8f054d1af4588dc5cSaya pikir ini lebih lengkap dengan ErrorView & EmptyView https://gist.github.com/henrytao-me/2f7f113fb5f2a59987e7
sumber
Anda bisa melukis teks pada
RecyclerView
saat kosong. Kebiasaan berikut subclass dukunganempty
,failed
,loading
, danoffline
mode. Agar kompilasi berhasil, tambahkanrecyclerView_stateText
warna pada resource Anda./** * {@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; } }
sumber
Dari sudut pandang saya, cara termudah untuk melakukan View kosong adalah membuat RecyclerView kosong baru dengan tata letak yang ingin Anda perbesar sebagai latar belakang. Dan Adaptor kosong ini disetel saat Anda memeriksa ukuran kumpulan data Anda.
sumber