SwipeRefresh is not working after setting an empty view for listview which is the only child of a SwipeRefresh layout. How to solve this issue?
-
16I have found the solution. We need to set android:clickable(true) for an empty view then it works fine. – Dinesh Apr 10 '14 at 06:21
-
Can you post the XML of your layout? I'm facing the same problem and can't seem to have it work with your solution. – Distwo May 16 '14 at 18:07
-
1I have added empty view, But I cannot swipe down this empty view to refresh. Can I get the solution for this.. Thanks in advance. – Ashokchakravarthi Nagarajan Jun 11 '14 at 10:39
-
@Dinesh, you should post your solution as an answer and accept it - that's a common SO practice. Ideally, with xml example. – Alexander Malakhov Mar 23 '15 at 08:13
-
Please see my solution (http://stackoverflow.com/a/40466223/6608860), It should work for this case as well. – Gaurav Karwa Nov 07 '16 at 13:24
9 Answers
Here is the solution: You can simply use this view hierarchy :
<FrameLayout ...>
<android.support.v4.widget.SwipeRefreshLayout ...>
<ListView
android:id="@android:id/list" ... />
</android.support.v4.widget.SwipeRefreshLayout>
<TextView
android:id="@android:id/empty" ...
android:text="@string/empty_list"/>
</FrameLayout>
Then, in code, you just call:
_listView.setEmptyView(findViewById(android.R.id.empty));
That's it.

- 6,338
- 2
- 29
- 38
-
4Nice, upvoted. But I have one more problem facing, which is I cannot swipe down this empty view to refresh. isn't it.. Can I get the solution for this.. Thanks in advance. @nitesh – Ashokchakravarthi Nagarajan Jun 11 '14 at 10:38
-
1you need to override canChildScrollUp() method which is in SwipeRefreshLayout class .check my answer here:http://stackoverflow.com/questions/23236650/swiperefreshlayout-in-android/23679420#23679420.This is for scroll view but you can put some logic for your own view – nitesh goel Jun 11 '14 at 13:28
-
3If you're gonna take someone else's answer and use it as yours at least give them the credit: http://stackoverflow.com/a/23424655/893130 – n1te Oct 11 '15 at 05:04
-
@niteshgoel please answer this too: http://stackoverflow.com/questions/36434071/android-support-v4-widget-swiperefreshlayout-working-but-it-is-not-visible – Apr 05 '16 at 18:37
-
@nitesh goel: I also facing the same problem that was faced by Ashok when using this solution. – Madhan Nov 17 '16 at 12:16
I had this issue too, and solved it without any additional code in the activity by using the layout below.
If you are using a ListActivity
or ListFragment
it handles showing/hiding the empty view for you, and refreshing works with an empty list as well with this layout structure.
No hacks needed, everything is in the SwipeRefreshLayout
, as it should be.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/Refresher"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null" />
<ScrollView
android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="Geen formulieren gevonden"
style="@style/text.EmptyView" />
</ScrollView>
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>
Hope this helps you. If so, don't forget to accept the answer.
Note: this is a duplicate of my answer to this question, but that question is pretty much a duplicate of this question... :)
UPDATE
If the SwipeRefreshLayout is activated too early, you can implement ListView.OnScroll with:
_refresher.Enabled = e.FirstVisibleItem == 0;
This disables the refresher until you scrolled to the top. This is only needed when using a ListView, the new RecyclerView works as expected.
-
1
-
-
Yes I did. The problem was, that when scrolling list down the swipe-refresh was being activated too early. CustomSwipeRefreshLayout described below works properly. – Malachiasz Feb 01 '16 at 08:52
The problem for me was that when the empty view was visible then the refreshing circle wasn't shown although the refreshing method worked. For me this code worked, I hope it helps.
the xml layout:
<FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true"> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="wrap_content" android:fadingEdge="none" android:footerDividersEnabled="false" android:headerDividersEnabled="false"/> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center"> <TextView android:id="@+id/empty_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" android:visibility="gone"/> </ScrollView> </FrameLayout>
the custom SwipeRefreshLayout:
package misc; import android.content.Context; import android.support.v4.widget.SwipeRefreshLayout; import android.widget.ListView; public class CustomSwipeRefreshLayout extends SwipeRefreshLayout { private ListView mListView; public CustomSwipeRefreshLayout(Context context) { super(context); } public void setListView(ListView listView) { mListView = listView; } @Override public boolean canChildScrollUp() { if (mListView == null) { return true; } return mListView.canScrollVertically(-1); } }
and in my Fragment where I use the layout I only set the swipe to refresh layout in this way:
mSwipeRefreshLayout.setListView(mListView);
the ListView's empty view is set in this way:
TextView emptyView = (TextView) view.findViewById(R.id.empty_view); emptyView.setText("No data"); mListView.setEmptyView(emptyView);
I hope it helps.

- 69
- 8
here's how i did this (probably not very elegant solution)
private void createEmptyView() {
ViewGroup parent = (ViewGroup) listView.getParent();
emptyView = (TextView) getLayoutInflater(null)
.inflate(R.layout.view_empty, parent, false);
parent.addView(emptyView);
listView.setEmptyView(emptyView);
}
public class FrameSwipeRefreshLayout extends SwipeRefreshLayout {
private ViewGroup listView;
public void setListView(ViewGroup list) {
listView = list;
}
@Override
public boolean canChildScrollUp() {
if (listView != null) {
View child = listView.getChildAt(0);
return child != null && child.getTop() != 0;
}
return super.canChildScrollUp();
}
}
empty layout
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:clickable="true" />
list layout
<FrameSwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
</FrameSwipeRefreshLayout>

- 3,743
- 2
- 24
- 27
-
I like this solution better than 2 SwipeRefreshLayouts as I have only one SRL to take care of. – kotucz Jan 12 '15 at 17:05
-
@orium please answer this too: http://stackoverflow.com/questions/36434071/android-support-v4-widget-swiperefreshlayout-working-but-it-is-not-visible – Apr 05 '16 at 18:37
You can check out this issue. I posted a work around solution.
I fixed this issue using two SwipeToRefreshLayouts.
- One for wrapping the ListView
- The other as an emptyView
I posted my code on GitHub.

- 18,291
- 10
- 66
- 81
-
-
2I moved the SwipeToRefreshLayout for the emptyView above the SwipeToRefreshLayout for the ListView and it works now. – Edward van Raak Aug 14 '14 at 10:08
As @Dinesh written above, i have used clickable="true"
like below with empty RecyclerView
:
mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setClickable(true);
myText.setVisibility(View.VISIBLE);
xml layout:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshKartvizitKisilerim"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
<TextView
android:id="@+id/myText"
android:visibility="gone"
android:text="@string/noListItem"
android:textSize="18sp"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
RecyclerView
has height match_parent
and SwipeRefresh
has wrap_content
. When there is item in list, don't forget to make text gone
.

- 9,501
- 5
- 69
- 106
I have another idea which works well. Subclass ListView and override setAdapter() and setEmptyView(). setEmptyView should just store the view to use for the empty view, and setAdapter should register a DataSetObserver that will hide/show the empty view without altering the list view's visibility. You would probably want to use a FrameLayout that holds your SwipeToRefreshLayout and an empty view (as siblings). You can then position the empty view at the top/middle/bottom etc pretty easily using gravity and layout gravity. You could also use a RelativeLayout but I haven't tried. You will want to somehow unregister the dataSetObserver, I believe you may want to do that in onDetachFromWindow as I did below.
public class SwipeToRefreshCompatibleList extends ListView {
private boolean mIsEmpty = false;
private View mEmptyView;
private Adapter mAdapter;
private DataSetObserver mLocalObserver = new DataSetObserver() {
@Override
public void onChanged() {
boolean isEmpty = mAdapter == null || mAdapter.getCount() == 0;
if (mEmptyView != null) {
if (isEmpty != mIsEmpty) {
mEmptyView.setVisibility(isEmpty ? View.VISIBLE : View.GONE);
}
}
mIsEmpty = isEmpty;
}
};
public SwipeToRefreshCompatibleList(Context context) {
super(context);
}
public SwipeToRefreshCompatibleList(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SwipeToRefreshCompatibleList(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SwipeToRefreshCompatibleList(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void setAdapter(ListAdapter adapter) {
mAdapter = adapter;
adapter.registerDataSetObserver(mLocalObserver);
super.setAdapter(adapter);
}
@Override
public void setEmptyView(View view) {
mEmptyView = view;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mLocalObserver);
}
}
}
Example layout file:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.company.widget.SwipeToRefreshCompatibleList
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/BasicList"
android:divider="@null"
/>
</android.support.v4.widget.SwipeRefreshLayout>
<TextView
android:padding="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_gravity="center"
android:textSize="18sp"
android:id="@android:id/empty"
/>
</FrameLayout>
While this takes a bit more code than simply subclassing ListView and altering setVisibility such that it won't set the list to GONE/HIDDEN, I feel like this is less of a hack and still allows the user to set the list to GONE/Hidden if they needed.

- 8,924
- 8
- 60
- 77
I have tried UI hack but it didn't work, the only solution worked is set adapter. pass empty value make sure the value will not be null.
NotificationListAdapter notificationListAdapter;
notificationListAdapter = new NotificationListAdapter(mContext,notificationResponse);
reCycleViewNotificationList.setAdapter(notificationListAdapter); // weather ListView or RecyclerView

- 1,497
- 12
- 19