17

SwipeRefresh 在为作为 SwipeRefresh 布局的唯一子项的 listview 设置空视图后不起作用。如何解决这个问题?

4

9 回答 9

22

这是解决方案:您可以简单地使用此视图层次结构:

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

然后,在代码中,您只需调用:

_listView.setEmptyView(findViewById(android.R.id.empty));

而已。

于 2014-05-15T11:07:54.293 回答
5

我也遇到了这个问题,并通过使用下面的布局在活动中没有任何额外代码的情况下解决了这个问题。

如果您使用的是,ListActivity或者ListFragment它会为您处理显示/隐藏空视图,并且刷新适用于空列表以及此布局结构。

无需 hack,一切都在SwipeRefreshLayout.

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

希望这对您有所帮助。如果是这样,请不要忘记接受答案。

注意:这是我对这个问题的回答的重复,但这个问题几乎是这个问题的重复...... :)

更新
如果 SwipeRefreshLayout 过早激活,您可以实现 ListView.OnScroll :

_refresher.Enabled = e.FirstVisibleItem == 0;

这会禁用刷新,直到您滚动到顶部。这仅在使用 ListView 时才需要,新的 RecyclerView 按预期工作。

于 2015-07-16T08:32:16.057 回答
3

对我来说问题是,当空视图可见时,尽管刷新方法有效,但没有显示刷新圆圈。对我来说,这段代码有效,我希望它有所帮助。

  • xml布局:

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

  • 自定义 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);
        }
    }
    
  • 在我使用布局的片段中,我只设置滑动以通过这种方式刷新布局:

    mSwipeRefreshLayout.setListView(mListView);
    
  • ListView 的空视图是这样设置的:

    TextView emptyView = (TextView) view.findViewById(R.id.empty_view);
    emptyView.setText("No data");
    mListView.setEmptyView(emptyView);
    

我希望它有所帮助。

于 2015-09-02T16:04:34.710 回答
2

我是这样做的(可能不是很优雅的解决方案)

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

空布局

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

列表布局

    <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>
于 2014-12-02T10:25:59.830 回答
1

你可以看看这个问题。我发布了一个解决方案。

Android - 带有空文本视图的 SwipeRefreshLayout

于 2014-04-12T02:21:26.963 回答
1

我使用两个 SwipeToRefreshLayouts 解决了这个问题。

  • 一种用于包装 ListView
  • 另一个作为emptyView

我在GitHub 上发布了我的代码。

于 2014-04-14T21:32:35.363 回答
0

我有另一个很好的想法。子类ListView并覆盖setAdapter()setEmptyView()setEmptyView应该只存储用于空视图的视图,并且 setAdapter应该注册一个DataSetObserver,它将隐藏/显示空视图而不改变列表视图的可见性。您可能希望使用一个 FrameLayout来保存您的SwipeToRefreshLayout和一个空视图(作为兄弟姐妹)。然后,您可以使用重力和布局重力很容易地将空视图定位在顶部/中间/底部等。您还可以使用RelativeLayout但我没试过。你会想以某种方式取消注册 dataSetObserver,我相信你可能想在 onDetachFromWindow 中这样做,就像我在下面所做的那样。

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

}

示例布局文件:

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

虽然这需要更多的代码而不是简单地继承 ListView 并更改 setVisibility 以便它不会将列表设置为 GONE/HIDDEN,但我觉得这不是一个 hack,并且仍然允许用户将列表设置为 GONE/Hidden如果他们需要。

于 2015-09-10T17:40:19.680 回答
0

正如上面写的@Dinesh,我使用clickable="true"了如下所示的空RecyclerView

mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setClickable(true);
myText.setVisibility(View.VISIBLE);

xml布局:

<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有高度match_parentSwipeRefreshwrap_content。当列表中有项目时,不要忘记制作 text gone

于 2015-08-06T12:50:53.983 回答
0

我尝试过 UI hack,但没有成功,唯一有效的解决方案是设置适配器。传递空值确保该值不会为空。

NotificationListAdapter notificationListAdapter;
notificationListAdapter = new NotificationListAdapter(mContext,notificationResponse);
reCycleViewNotificationList.setAdapter(notificationListAdapter); // weather ListView or RecyclerView
于 2019-08-27T14:39:02.377 回答