Empty View on a RecyclerView

廉价感情. 提交于 2019-12-06 16:17:24

I updated your code:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:name="com.github.jlcarveth.grocer.layout.fragment.GroceryListFragment"
android:layout_width="match_parent"
tools:context="com.github.jlcarveth.grocer.layout.fragment.GroceryListFragment"
android:layout_height="match_parent">

<android.support.v7.widget.RecyclerView
    android:id="@+id/grocery_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginLeft="0dp"
    android:layout_marginRight="0dp"
    app:layoutManager="LinearLayoutManager"
    tools:listitem="@layout/grocery_item" />

<TextView
    android:id="@+id/empty_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:visibility="gone"
    android:text="NO DATA AVAILABLE" />
</FrameLayout>

Your Fragment:

 @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {


  View view = inflater.inflate(R.layout.fragment_grocerylist, container, false);

    rv = view.findViewById(R.id.grocery_list);
    TextView emptyView = (TextView)view.findViewById(R.id.empty_view);

    dh = new DatabaseHandler(view.getContext());

    dataset = dh.getGroceries();


     Context context = view.getContext();
     RecyclerView recyclerView = (RecyclerView) rv;
     recyclerView.setLayoutManager(new LinearLayoutManager(context));

     adapter = new GroceryListRecyclerViewAdapter(dataset,mListener,this);
     recyclerView.setAdapter(adapter);


    ItemTouchHelper.Callback callback = new SimpleTouchHelperCallback(adapter);
    ith = new ItemTouchHelper(callback);
    ith.attachToRecyclerView(recyclerView);

    DividerItemDecoration div = new DividerItemDecoration(recyclerView.getContext(),
            DividerItemDecoration.VERTICAL);

    recyclerView.addItemDecoration(div);


    if (dataset.isEmpty()){
        recyclerView.setVisibility(View.GONE);
         emptyView.setVisibility(View.VISIBLE);
    } else {
         recyclerView.setVisibility(View.VISIBLE);
         emptyView.setVisibility(View.GONE);
    }



    return view;
}

Add a textview to your layout. At the same level as the RecyclerView

<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" />

At the onCreate or the appropriate callback check to see if the dataset that feeds your RecyclerView is empty. If it is then the RecyclerView is empty too. In that case, the message appears on the screen. If not, change its visibility:

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

Why don't you go for a Relative layout.

<Relative layout>
    <Recycler View/>

    <Text View/>
</Relative layout

As the array is empty

  RecyclerView.GONE
   TextView.VISIBLE

and if the array is having some data

  RecyclerView.VISIBLE
  TextView.GONE

In my case, I am following this only.

If doesn't work, I'll send you my code.

When I faced this issue, while surfing the web I found useful gist https://gist.github.com/sheharyarn/5602930ad84fa64c30a29ab18eb69c6e.

Here shown how to implement empty view in elegant way by defining data observer.

This answer is for developers using Kotlin and databinding in their Android project.

custom_recyclerview_empty_support.xml

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Recycler view -->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!-- Empty view -->
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/empty_text_view"
        style="@style/TextAppearance.MaterialComponents.Body1"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@color/white_light"
        android:gravity="center"
        android:textColor="@color/black_light"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Empty View" />

    <!-- Retry view -->
    <androidx.appcompat.widget.LinearLayoutCompat
        android:id="@+id/retry_linear_layout_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@color/white_light"
        android:gravity="center"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/retry_text_view"
            style="@style/TextAppearance.MaterialComponents.Body1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/views_pad_horizontal"
            android:layout_marginTop="@dimen/views_pad_vertical"
            android:layout_marginEnd="@dimen/views_pad_horizontal"
            android:layout_marginBottom="@dimen/views_pad_vertical"
            android:gravity="center"
            tools:text="Retry View" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/retry_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/retry_button" />
    </androidx.appcompat.widget.LinearLayoutCompat>

    <!--  Loading view -->
    <FrameLayout
        android:id="@+id/loading_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@color/white_light"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ProgressBar
            android:id="@+id/progress_bar"
            style="?android:attr/progressBarStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center" />
    </FrameLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

The fragment class where I am using this Custom RecyclerView class

     <app.ui.widgets.RecyclerViewEmptySupport
            android:id="@+id/my_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

Creating a Custom RecyclerView class :

class RecyclerViewEmptySupport(context: Context, attrs: AttributeSet) :
ConstraintLayout(context, attrs) {

private val binding: CustomRecyclerviewEmptySupportBinding
val recyclerView: RecyclerView

init {
    this.binding =
        CustomRecyclerviewEmptySupportBinding.inflate(LayoutInflater.from(context), this, true)
    this.recyclerView = binding.recyclerView
}

fun updateViews(
    loading: Boolean = false,
    retry: Boolean = false,
    empty: Boolean = false,
    success: Boolean = false
) {
    binding.recyclerView.setVisibleOrGone(success)
    binding.emptyTextView.setVisibleOrGone(empty)
    binding.retryLinearLayoutView.setVisibleOrGone(retry)
    binding.loadingView.setVisibleOrGone(loading)
}

// Empty view
fun showEmptyMessage(message: String) {
    updateViews(empty = true)
    binding.emptyTextView.text = message
}

// Retry view
fun showRetryView(message: String, callback: () -> Unit) {
    updateViews(retry = true)

    binding.retryTextView.text = message
    binding.retryButton.setOnClickListener { callback() }
}
}

The Fragment/Activity class can manage the Views visibility and setting data to views , like this :

When api is to be called , call this block of code ,

 binding.myRecyclerView.updateViews(loading = true)
 getDataFromRepository()

When data is empty in api response , call this,

binding.myRecyclerView.showEmptyMessage("No Items Message")

When data exists in api , call this ,

 list.addAll(apiList)
 adapter.notifyDataSetChanged()

 binding.myRecyclerView.updateViews(success = true)

When there is some error in api response , call this

 binding.myRecyclerView.showRetryView("Unable to get data at the moment.") { getDataFromRepository() }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!