Android support v4 SwipeRefreshLayout empty view issue

眉间皱痕 提交于 2019-11-29 16:56:07

问题


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?


回答1:


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.




回答2:


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.




回答3:


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.




回答4:


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>



回答5:


You can check out this issue. I posted a work around solution.

Android - SwipeRefreshLayout with empty textview




回答6:


I fixed this issue using two SwipeToRefreshLayouts.

  • One for wrapping the ListView
  • The other as an emptyView

I posted my code on GitHub.




回答7:


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.




回答8:


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.




回答9:


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


来源:https://stackoverflow.com/questions/22959118/android-support-v4-swiperefreshlayout-empty-view-issue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!