Как показать пустой вид с помощью RecyclerView?
Я привык помещать специальный вид внутри файла макета как описано в ListActivity
документация на отображается, когда нет данных. Это представление имеет 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" />
интересно, как это можно сделать с новым RecyclerView
?
11 ответов
на том же макете, где определяется RecyclerView
добавить 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" />
на onCreate
или соответствующий обратный вызов вы проверяете, если набор данных, который кормит ваш RecyclerView
пусто.
Если набор данных пуст, то RecyclerView
слишком пусто. В этом случае на экране появится сообщение.
Если нет, измените его видимость:
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);
}
для моих проектов я принял это решение (RecyclerView
С setEmptyView
способ):
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;
}
}
и вы должны использовать его вместо RecyclerView
класс:
<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"
/>
и
RecyclerViewEmptySupport list =
(RecyclerViewEmptySupport)rootView.findViewById(R.id.list1);
list.setLayoutManager(new LinearLayoutManager(context));
list.setEmptyView(rootView.findViewById(R.id.list_empty));
вот решение, использующее только пользовательский адаптер с другим типом представления для пустой ситуации.
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);
}
}
}
Я использую 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>
в коде вы проверите курсор / набор данных и переключите представления.
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();
}
}
также вы можете установить анимацию, если хотите, с помощью нескольких строк кода
mListSwitcher.setInAnimation(slide_in_left);
mListSwitcher.setOutAnimation(slide_out_right);
на проверьте, имеет ли адаптер 0 элементов и верните другой тип представления, если это так.
на onCreateViewHolder
проверьте, является ли viewType тем, который вы вернули ранее, и надуйте другой вид. В этом случае файл макета с этим TextView
редактировать
если это все еще не работает, вы можете установить размер представления программно следующим образом:
Point size = new Point();
((WindowManager)itemView.getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getSize(size);
и после этого когда вы надуете ваше просмотр вызова:
inflatedView.getLayoutParams().height = size.y;
inflatedView.getLayoutParams().width = size.x;
RVEmptyObserver
вместо использования пользовательского RecyclerView
, использование AdapterDataObserver
является более простым решением, которое позволяет установить пользовательский View
это отображается, когда в списке нет элементов:
Пример Использования:
RVEmptyObserver observer = new RVEmptyObserver(recyclerView, emptyView)
rvAdapter.registerAdapterDataObserver(observer);
класс:
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(); }
}
поскольку ответ Кевина не завершен.
Это более правильный ответ, если вы используете RecyclerAdapter
' s notifyItemInserted
и notifyItemRemoved
для обновления набора данных.
Просто добавьте ниже коды.
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);
}
});
вот мой класс для показа пустого представления, повторите просмотр (когда не удалось загрузить api) и ход загрузки для 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>
источник здесь https://github.com/PhanVanLinh/AndroidRecyclerViewWithLoadingEmptyAndRetry
добавил RecyclerView
и альтернатива ImageView
до 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>
и затем в Adapter
:
@Override
public int getItemCount() {
if (mOrders.size() == 0) {
mRecyclerView.setVisibility(View.INVISIBLE);
} else {
mRecyclerView.setVisibility(View.VISIBLE);
}
return mOrders.size();
}
просто incase вы работаете с FirebaseRecyclerAdapter этот пост работает как шарм https://stackoverflow.com/a/39058636/6507009
попробуй listView
, addFooterView
после добавления адаптера к listview
listview.setAdapter(adapter);
listview.addFooterView(emptyView);