Equivalent of ListView.setEmptyView in RecyclerView

前端 未结 13 1664
孤街浪徒
孤街浪徒 2020-11-30 17:44

In RecyclerView, I want to set an empty view to be shown when the adapter is empty. Is there an equivalent of ListView.setEmptyView()?

相关标签:
13条回答
  • 2020-11-30 17:48

    Try RVEmptyObserver:

    It's an implementation of an AdapterDataObserver that allows you to simply set a View as the default empty layout for your RecylerView. This way, instead of using a custom RecyclerView and making your life harder, you can easily use it with your existing code:


    Example Usage:

    RVEmptyObserver observer = new RVEmptyObserver(recyclerView, emptyView)
    rvAdapter.registerAdapterDataObserver(observer);
    

    You can see the code and example usage in an actual app here.


    Class:

    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(); }
    }
    
    0 讨论(0)
  • 2020-11-30 17:55

    I would prefer to implement this functionality in Recycler.Adapter

    On your overridden getItemCount method, inject empty check codes there:

    @Override
    public int getItemCount() {
        if(data.size() == 0) listIsEmtpy();
        return data.size();
    }
    
    0 讨论(0)
  • 2020-11-30 18:01

    Solution provided in this link seems perfect. It uses viewType to identify when to show emptyView. No need to create custom RecyclerView

    Adding code from the above link:

    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;
    }
    
    }
    
    0 讨论(0)
  • 2020-11-30 18:03

    With the new data binding feature you can also achieve this in your layout directly:

    <TextView
       android:text="No data to display."
       android:visibility="@{dataset.size() > 0 ? View.GONE : View.VISIBLE}" />
    

    In that case you just need to add a variable and an import to the data section of your XML:

    <data>
    <import type="android.view.View"/>
    <variable
        name="dataset"
        type="java.util.List&lt;java.lang.String&gt;"
        />
    </data>
    
    0 讨论(0)
  • 2020-11-30 18:04

    I would simply prefer a simple solution like,

    have your RecyclerView inside a FrameLayout or RelativeLayout with a TextView or other view with showing empty data message with visibility GONE by default and then in the adapter class, apply the logic

    Here, I have one TextView with message no data

    @Override
    public int getItemCount() {
        textViewNoData.setVisibility(data.size() > 0 ? View.GONE : View.VISIBLE);
        return data.size();
    }
    
    0 讨论(0)
  • 2020-11-30 18:04

    If you want to support more states such as loading state, error state then you can checkout https://github.com/rockerhieu/rv-adapter-states. Otherwise supporting empty view can be implemented easily using RecyclerViewAdapterWrapper from (https://github.com/rockerhieu/rv-adapter). The main advantage of this approach is you can easily support empty view without changing the logic of the existing adapter:

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

    Usage:

    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);
    
    0 讨论(0)
提交回复
热议问题