如何使用 RecyclerView 显示空视图?

Posted

技术标签:

【中文标题】如何使用 RecyclerView 显示空视图?【英文标题】:How to show an empty view with a RecyclerView? 【发布时间】:2015-03-28 20:08:51 【问题描述】:

我习惯在布局文件中放置一个特殊的视图作为described in the ListActivity documentation,以便在没有数据时显示。此视图的 ID 为 "android:id/empty"

<TextView
    android:id="@android:id/empty"
    android:layout_
    android:layout_
    android:text="@string/no_data" />

我想知道如何使用新的RecyclerView 来做到这一点?

【问题讨论】:

你可以使用github.com/rockerhieu/rv-adapter-states,它不仅支持空视图,还支持加载视图和错误视图。而且你可以在不改变现有适配器逻辑的情况下使用它。 令人着迷的是,似乎没有一个简单的setEmptyView() 方法来对抗RecyclerView... 这是我的答案,请查看此链接***.com/a/58411351/5449220 @Subby,同意,但setEmptyView() 也有劣势。加载数据时,我们不想在ListView 中显示空视图,但确实如此。所以,我们必须实现一些逻辑。目前我使用***.com/a/48049142/2914140。 【参考方案1】:

在定义RecyclerView 的同一布局上,添加TextView

<android.support.v7.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_
    android:layout_
    android:scrollbars="vertical" />

<TextView
    android:id="@+id/empty_view"
    android:layout_
    android:layout_
    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);

【讨论】:

这对我不起作用,因为回收站视图布局在片段中膨胀,而决定是显示正常项目布局还是无项目布局是在适配器中做出的。 @JJD 在使用片段时,同样适用。当你膨胀你的片段视图时,你有 recyclerview,然后是另一个用于你的空视图的布局。通常在我的片段中,我会有以下视图:1)recyclerview,2)空视图,3)进度条视图。无论列表是什么,我通常都会传递适配器,但根据列表的大小,我将隐藏 recyclerview 并显示空的,反之亦然。如果 recyclerview 有一个空列表,那么它不会对它做任何事情。你只会看到一个空视图。 @stackex 验证必须在Fragment的onCreateView回调或者Activity的onResume中。这样,验证将在屏幕显示给用户之前立即进行,并且适用于两者,增加或减少数据集中的行数。 @Zapnologica 您可以反过来做:使用事件总线(例如 greenrobots Eventbus 或 Otto),然后在数据集更改时将适配器发布到事件总线上。在片段中,您所做的只是创建一个方法,其参数对应于适配器传递给 Eventbus.post 方法的参数,然后相应地更改布局。一种更简单但也更耦合的方法是在适配器中创建一个回调接口,并在创建适配器时让片段实现它。 在布局中我得到了多个根标签。您的完整布局文件是什么样的?【参考方案2】:

对于我的项目,我提出了这个解决方案(RecyclerViewsetEmptyView 方法):

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

<com.maff.utils.RecyclerViewEmptySupport android:id="@+id/list1"
    android:layout_
    android:layout_
    />

<TextView android:id="@+id/list_empty"
    android:layout_
    android:layout_
    android:text="Empty"
    />

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

【讨论】:

您是从this answer 或from here 获取此代码的吗? @Sufian 不,我没有看到那个答案,只是找到了同样的方法。但是那段代码肯定比我的更漂亮:) 我尝试将它与 FirebaseRecyclerAdapter 结合使用,但没有成功。这是因为 FirebaseRecyclerAdapter 不调用(AdapterDataObserver 的)onChange,而是调用 onItem*-methods。要使其工作,请添加:` Override public void onItemRangeRemoved(int positionStart, int itemCount) //check Override public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) //the check //etc.. ` 为什么在观察者中检查适配器是否为空?如果适配器为 null,则永远不应调用观察者。 呃,我必须说这只是经典的 Google BS。我必须实现这个只是为了添加一个空视图?它应该包含在他们的 cr@psh1t SDK 中!看在上帝的份上!【参考方案3】:

这是一个解决方案,仅使用具有不同视图类型的自定义适配器来处理空情况。

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


【讨论】:

@sfk92fksdf 为什么容易出错?这是您应该在 recyclerview 中处理多种视图类型的方式 @billynomates,因为getItemCount() 应该是一个单行符,但这里我们有一个不平凡的if,其中包含一些隐藏的逻辑。这个逻辑在getItemViewType 中也显得很尴尬,天知道还有哪里 不需要是一行。如果您有多种视图类型,则可以这样做。 @sfk92fksdf 你说的隐藏逻辑是什么意思?代码就在上面▲ 在我看来,这个答案应该是公认的答案。这确实是处理多种视图类型的方式【参考方案4】:

我使用 ViewSwitcher

<ViewSwitcher
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:id="@+id/switcher"
    >

    <android.support.v7.widget.RecyclerView
        android:id="@+id/list"
        android:layout_
        android:layout_
        />

    <TextView android:id="@+id/text_empty"
        android:layout_
        android:layout_
        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);

【讨论】:

真的很新奇 清洁解决方案。【参考方案5】:

由于凯文的回答不完整。 如果您使用RecyclerAdapternotifyItemInsertednotifyItemRemoved 更新数据集,这是更正确的答案。 请参阅下面另一个用户添加的 Kotlin 版本。

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

科特林

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

【讨论】:

这是一个很好的解决方案。我建议对其进行编辑,其中将包括 kotlin 版本。 这看起来不错,但如果您多次调用 swapAdapter() 甚至 setAdapter() 可能不起作用。 我认为是最优雅的解决方案! 伟大的工作。显示标签时不要忘记隐藏RecyclerView 这是完美的答案。 +1【参考方案6】:

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

【讨论】:

相信在onChanged()onItemRangeInserted()不调用checkIfEmpty()会跑得更快 我同意(这就是我个人所做的),但这只是作为面临此问题的人们的起点。 最佳完美答案!!【参考方案7】:

在适配器的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;

【讨论】:

听起来不错。但是,当我的数据集为null 或为空时,我不会进入onCreateViewHolder,因为我必须在getItemCount 中返回0 如果为null则返回1:) 有点作用。谢谢你。 - 次要细节是我无法在回收站视图中获得垂直居中的空列表项。文本视图仍位于屏幕顶部,但我为父回收器视图设置了 android:layout_gravity="center"android:layout_height="match_parent" 这取决于您使用的行的布局。它应该 match_parent 在它的高度上。如果仍然无法使其工作,请添加一个全局布局侦听器并将其布局参数设置为与屏幕具有相同的高度和宽度。 所有容器(活动、片段、线性布局、回收器视图、文本视图)都设置为android:layout_height="match_parent"。虽然该行没有扩展到屏幕高度。【参考方案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

【讨论】:

【参考方案9】:

在自定义 RecyclerView 中使用 AdapterDataObserver

科特林:

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_
    android:layout_
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/emptyView"
        android:layout_
        android:layout_
        android:background="@color/white"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:id="@+id/emptyLabelTv"
            android:layout_
            android:layout_
            android:text="empty" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/loadingView"
        android:layout_
        android:layout_
        android:background="@color/white"
        android:gravity="center"
        android:orientation="vertical">

        <ProgressBar
            android:id="@+id/progressBar"
            android:layout_
            android:layout_
            android:layout_gravity="center"
            android:indeterminate="true"
            android:theme="@style/progressBarBlue" />
    </LinearLayout>

    <com.peeyade.components.recyclerView.RecyclerViewEmptyLoadingSupport
        android:id="@+id/recyclerView"
        android:layout_
        android:layout_ />
</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

【讨论】:

如果您采用该解决方案,请注意使用枚举是不够的,因为它增加了内存分配大小。根据您的上下文使用 Integer 或 String 并带有适当的 StringDefIntDef 注释 @AndriiArtamonov 不,没关系。使用枚举 - ***.com/a/54893141/2371425【参考方案10】:

我在RelativeLayout 中添加了RecyclerView 和替代ImageView

<RelativeLayout
    android:layout_
    android:layout_>

    <ImageView
        android:id="@+id/no_active_jobs"
        android:layout_
        android:layout_
        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_
        android:layout_ />

</RelativeLayout>

然后在Adapter:

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

【讨论】:

如何在Adapter内联系mRecyclerView 将Adapter绑定到特定的Activity并不是好的设计模式。最好通过接口来做到这一点 这也会导致布局过度绘制,不建议这样做,它可能会导致一些性能问题。更多详情请见youtube.com/watch?v=T52v50r-JfE【参考方案11】:

另一种方法是使用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);
            
        );

【讨论】:

【参考方案12】:

最简单的解决方案是使用 RecyclerView.AdapterDataObserver 并在您的适配器初始化后将其注册到您的 recyclerview 中。

val emptyDataObserver = EmptyDataObserver(recycler_view, empty_data_parent)
yourAdapter.registerAdapterDataObserver(emptyDataObserver)

其中,recycler_view 和 empty_data_parent 是 Activity 中的布局,根据需要限制这些视图并使其可见性GONE。然后使用图像和文本创建您自己的空数据集视图。

 <include
            android:id="@+id/empty_data_parent"
            layout="@layout/item_empty_dataset"
            android:layout_
            android:visibility="gone"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintTop_toBottomOf="parent"
            android:layout_
            android:layout_gravity="center" />

这是 empty_data_set_view.xml

的示例
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    android:orientation="vertical"
    android:layout_gravity="center"
    android:gravity="center"
    android:paddingTop="10dp"
    android:paddingBottom="10dp"
    tools:ignore="RtlHardcoded">

    <ImageView
        android:id="@+id/imageView2"
        android:layout_
        android:layout_
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.422"
        android:src="@drawable/ic_empty_dataset_1" />

    <TextView
        android:id="@+id/title"
        android:layout_
        android:layout_
        android:text="Title is called when title is placed"
        android:padding="10dp"
        android:fontFamily="@font/normal"
        android:textStyle="bold"
        android:gravity="center"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView2" />

    <TextView
        android:id="@+id/sub_title"
        android:layout_
        android:layout_
        android:text=" Subtitle is called when title is placed. Subtitle is called when title is placed"
        android:padding="5dp"
        android:fontFamily="@font/normal"
        android:gravity="center"
        android:layout_marginStart="10dp"
        android:layout_marginEnd="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/title" />
</androidx.constraintlayout.widget.ConstraintLayout>

这个 EmptyDataObserver 类将完成这项工作。

import android.view.View
import androidx.recyclerview.widget.RecyclerView


class EmptyDataObserver constructor(rv: RecyclerView?, ev: View?): RecyclerView.AdapterDataObserver() 

    private var emptyView: View? = null
    private var recyclerView: RecyclerView? = null

    init 
        recyclerView = rv
        emptyView = ev
        checkIfEmpty()
    


    private fun checkIfEmpty() 
        if (emptyView != null && recyclerView!!.adapter != null) 
            val emptyViewVisible = recyclerView!!.adapter!!.itemCount == 0
            emptyView!!.visibility = if (emptyViewVisible) View.VISIBLE else View.GONE
            recyclerView!!.visibility = if (emptyViewVisible) View.GONE else View.VISIBLE
        
    

    override fun onChanged() 
        super.onChanged()
        checkIfEmpty()
    

    override fun onItemRangeChanged(positionStart: Int, itemCount: Int) 
        super.onItemRangeChanged(positionStart, itemCount)
    


【讨论】:

【参考方案13】:

如果你正在使用 FirebaseRecyclerAdapter,这篇文章就像一个魅力 https://***.com/a/39058636/6507009

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。【参考方案14】:

如果您想在回收站视图为空时显示文本视图,您可以这样做:

ArrayList<SomeDataModel> arrayList = new ArrayList<>();

RecycleAdapter recycleAdapter =  new RecycleAdapter(getContext(),project_Ideas);

recyclerView..setAdapter(recycleAdapter);

if(arrayList.isEmpty())

    emptyTextView.setVisibility(View.VISIBLE);
    recyclerView.setVisibility(View.GONE);

我假设你有 TextView

和这样的XML

 android:visibility="gone"

    
  

【讨论】:

【参考方案15】:

这是如何在 使用 LiveData 过滤和更新 RecyclerView 时显示 空视图

    ViewModel.getInstance().getCustomers?.observe(viewLifecycleOwner, customerList ->
           //assign your adapter with your list then
        listAdapter?.notifyDataSetChanged()
        isListItemEmpty(customerList?.isEmpty())

创建一个接口来在适配器和片段之间进行通信并在适配器内部注册它

 interface EmptyListener 
            fun isListEmpty(isEmpty: Boolean)
        

然后在 publishResults 中调用它:

        dataList?.isEmpty()?.let  mListener?.isListEmpty(it) 

最后在 Fragment 中实现你的接口:

 override fun isListEmpty(isEmpty: Boolean) 
        if (isEmpty) 
            your_list?.visibility = View.GONE
            empty_view?.visibility = View.VISIBLE
         else 
            empty_view?.visibility = View.GONE
            your_list?.visibility = View.VISIBLE
        
    

【讨论】:

以上是关于如何使用 RecyclerView 显示空视图?的主要内容,如果未能解决你的问题,请参考以下文章

回收站视图 - 在空对象引用上

如何在 RecyclerView 中选择和取消选择项目?如何仅在回收站视图中突出显示所选项目?

java RecyclerView with provosion添加像列表视图的空视图。数据集为空时显示

如何知道何时显示布局中的特定视图在RecyclerView中

如何使用光标和循环显示来自 sqlite 的片段的 recyclerview

如何防止android应用程序由于recyclerview中的空列表而崩溃? [复制]