Как показать пустой вид с RecyclerView?

271

Я привык помещать специальный вид в файл макета, как описано в ListActivityдокументации, который будет отображаться, когда нет данных . Это представление имеет идентификатор "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?

JJD
источник
2
Вы можете использовать github.com/rockerhieu/rv-adapter-states , он поддерживает не только пустое представление, но также загрузочное представление и представление ошибок. И вы можете использовать его без изменения логики существующего адаптера.
Хиеу Рокер
20
Это просто увлекательно, что, кажется, нет простого setEmptyView()метода против RecyclerView...
Subby
Вот мой ответ, пожалуйста, проверьте эту ссылку stackoverflow.com/a/58411351/5449220
Rakesh Verma
@ Subby, согласен, но setEmptyView()тоже имел недостаток. При загрузке данных мы не хотели показывать пустое представление ListView, но оно появилось. Итак, нам пришлось реализовать некоторую логику. В настоящее время я использую stackoverflow.com/a/48049142/2914140 .
CoolMind

Ответы:

306

На том же макете, где определено 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);
}
slellis
источник
11
Это не работает для меня, потому что макет представления рециркулятора раздут во фрагменте, тогда как решение, показывать ли нормальное расположение элементов или расположение без элементов, принимается в адаптере.
JJD
1
@JJD при использовании фрагмента применяется то же самое. Когда вы раздуете свой фрагментный вид, у вас будет просмотрщик и другой макет, который будет использоваться для вашего пустого представления. Обычно в моих фрагментах у меня будут следующие представления: 1) просмотр вторичного окна, 2) пустой просмотр и 3) просмотр индикатора выполнения. Я обычно передаю адаптер, какой бы ни был список, но в зависимости от размера списка я либо скрываю обзор утилизатора и показываю пустой, либо наоборот. Если в списке переработчиков есть пустой список, он ничего с ним не делает. Вы просто видите пустой вид.
Рэй Хантер
1
@stackex Проверка должна быть в обратном вызове onCreateView фрагмента или onResume действия. Таким образом, проверка будет выполнена непосредственно перед отображением экрана пользователю и будет работать как для увеличения, так и для уменьшения количества строк в наборе данных.
slellis
2
@Zapnologica Вы можете сделать это наоборот: используйте шину событий (например, зеленую роботу или шину Отто), а затем разместите пост адаптера на шине событий при изменении набора данных. Во фрагменте все, что вы делаете, - это создаете метод, параметры которого соответствуют тому, что Adapter передает в метод Eventbus.post, и затем соответственно меняете компоновку. Более простой, но в то же время более сложный подход заключается в создании интерфейса обратного вызова в адаптере, а при создании адаптера его реализует фрагмент.
AgentKnopf
2
В макете я получаю несколько корневых тегов. Как выглядит ваш полный файл макета?
powder366
192

Для своих проектов я сделал это решение ( 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));
maff91
источник
2
Вы взяли этот код из этого ответа или отсюда ?
Суфиан
@ Суфиан Нет, я не видел этот ответ, просто нашел то же самое. Но этот код определенно выглядит красивее, чем мой :)
maff91
2
Я пытался объединить это с FirebaseRecyclerAdapter, он не работал. Это связано с тем, что FirebaseRecyclerAdapter не вызывает onChange (из AdapterDataObserver), а вызывает onItem * -методы. Чтобы заставить его работать, добавьте: `Переопределить public void onItemRangeRemoved (int positionStart, int itemCount) {// the check} Переопределить public void onItemRangeMoved (int fromPosition, int toPosition, int itemCount) {// проверка} // и т.д ..`
FrankkieNL
1
Почему вы проверяете, является ли адаптер нулевым в наблюдателе? если адаптер нулевой, наблюдатель никогда не должен вызываться.
Stimsoni
16
тьфу, я должен сказать, что это просто классический Google BS. Я должен реализовать это, чтобы добавить пустое представление? Это должно быть включено в их cr @ psh1t SDK! Ради Бога!
Neon Warge
62

Вот решение, использующее только пользовательский адаптер с другим типом представления для пустой ситуации.

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

}
radu122
источник
3
@ sfk92fksdf Почему это подвержено ошибкам? Это способ, которым вы должны обрабатывать несколько типов представлений в программе
повторного
@billynomates, потому что он getItemCount()должен быть простым, но здесь у нас есть нетривиальное ifс некоторой скрытой логикой. Эта логика также появляется неловко, getItemViewTypeи бог знает, где еще
Алексей Андронов
3
Это не должно быть одной строкой. Если у вас есть несколько типов представлений, это способ сделать это.
MSpeed
@ sfk92fksdf Что вы подразумеваете под скрытой логикой? Код прямо там ▲
radu122
1
по моему мнению, этот ответ должен быть принятым ответом. Это действительно способ работать с типами
Иво
45

Я использую 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);
wnc_21
источник
Это действительно роман
Чжан Сян,
Чистый раствор.
Оджонугва Джуд Очалифу
30

Так как ответ Кевина не полный.
Это более правильный ответ, если вы используете RecyclerAdapters notifyItemInsertedи notifyItemRemovedдля обновления набора данных. Посмотрите версию Kotlin, добавленную другим пользователем ниже.

Ява:

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

Котлин

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)
    }
})
wonsuc
источник
2
Это отличное решение. Я предлагаю изменить его, который будет включать версию kotlin.
jungledev
Это кажется хорошим, но может не сработать, если вы вызываете swapAdapter () или даже setAdapter () более одного раза.
Главк
Я думаю, что это самое элегантное решение!
энтузиаст андроид
Отличная работа. не забудьте скрыть RecyclerView при отображении метки
MrG
18

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(); }
}
Sheharyar
источник
Я считаю , что он будет работать быстрее , если вы не вызываете checkIfEmpty()в onChanged()иonItemRangeInserted()
Geekarist
Я согласен (и это то, что я лично сделал), но это должно было стать отправной точкой для людей, сталкивающихся с этой проблемой.
Sheharyar
9

На вашем адаптере getItemViewTypeпроверьте, имеет ли адаптер 0 элементов, и верните другой viewType, если это так.

Затем 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;
Педро Оливейра
источник
Звучит хорошо. Однако я не получаю в onCreateViewHolderкогда мой набор данных nullили пустой , так как я должен вернуться 0в getItemCount.
JJD
Затем верните 1, если он нулевой :)
Педро Оливейра
Работает несколько. Спасибо. - Незначительная деталь в том, что я не могу получить пустой элемент списка по центру по вертикали в представлении переработчика. Текстовое представление остается в верхней части экрана, тем не менее, я установил android:layout_gravity="center"и android:layout_height="match_parent"для родительского представления переработчика.
JJD
Это зависит от расположения строки, которую вы используете. Это должно соответствовать match_parent на его высоте. Если вы по-прежнему не можете заставить его работать, добавьте прослушиватель глобального макета и установите его параметры макета такими же, как высота и ширина экрана.
Педро Оливейра
Все контейнеры (активность, фрагмент, линейный макет, вид переработчика, текстовый вид) установлены в android:layout_height="match_parent". Хотя ряд не расширяется до высоты экрана.
JJD
8

Вот мой класс для показа пустого представления, повторного просмотра (когда загрузка 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

Фан Ван Линь
источник
7

Используйте AdapterDataObserver в пользовательском RecyclerView

Котлин:

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
            this@RecyclerViewEmptyLoadingSupport.visibility = View.GONE
        } else {
            emptyStateView?.visibility = View.GONE
            loadingStateView?.visibility = View.GONE
            this@RecyclerViewEmptyLoadingSupport.visibility = View.VISIBLE
        }
    }

    private fun setState() {

        when (this.stateView) {
            RecyclerViewEnum.LOADING -> {
                loadingStateView?.visibility = View.VISIBLE
                this@RecyclerViewEmptyLoadingSupport.visibility = View.GONE
                emptyStateView?.visibility = View.GONE
            }

            RecyclerViewEnum.NORMAL -> {
                loadingStateView?.visibility = View.GONE
                this@RecyclerViewEmptyLoadingSupport.visibility = View.VISIBLE
                emptyStateView?.visibility = View.GONE
            }
            RecyclerViewEnum.EMPTY_STATE -> {
                loadingStateView?.visibility = View.GONE
                this@RecyclerViewEmptyLoadingSupport.visibility = 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>

в деятельности используйте этот способ:

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
Расул Мири
источник
1
Если вы используете это решение, обратите внимание, что использование перечислений недостаточно из-за увеличенного размера памяти. Используйте Integer или String в зависимости от вашего контекста с соответствующими StringDefили IntDefаннотациями
Андрей Артамонов
2

Я добавил 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();
}
YTerle
источник
7
как добраться mRecyclerViewвнутриAdapter
Башир АЛЬ-МОМАНИ
2
Неправильный шаблон проектирования - привязывать Адаптер к конкретному виду деятельности. Лучше сделать это через интерфейсы
ruX
1
Кроме того, это вызывает переопределение макета, что не рекомендуется и может вызвать некоторые проблемы с производительностью. См. Youtube.com/watch?v=T52v50r-JfE для получения более подробной информации
Фелипе Конде
1

Еще один способ - использовать, addOnChildAttachStateChangeListenerкоторый обрабатывает появление / исчезновение дочерних представлений в RecyclerView.

recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
            @Override
            public void onChildViewAttachedToWindow(@NonNull View view) {
                forEmptyTextView.setVisibility(View.INVISIBLE);
            }

            @Override
            public void onChildViewDetachedFromWindow(@NonNull View view) {
                forEmptyTextView.setVisibility(View.VISIBLE);
            }
        });
HIDD
источник
0

Просто если вы работаете с FirebaseRecyclerAdapter, этот пост работает как очарование https://stackoverflow.com/a/39058636/6507009

knightcube
источник
7
Хотя эта ссылка может ответить на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если связанная страница изменится.
Ан Фам