SwipeRefresh 在为作为 SwipeRefresh 布局的唯一子项的 listview 设置空视图后不起作用。如何解决这个问题?
9 回答
这是解决方案:您可以简单地使用此视图层次结构:
<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));
而已。
我也遇到了这个问题,并通过使用下面的布局在活动中没有任何额外代码的情况下解决了这个问题。
如果您使用的是,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 按预期工作。
对我来说问题是,当空视图可见时,尽管刷新方法有效,但没有显示刷新圆圈。对我来说,这段代码有效,我希望它有所帮助。
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);
我希望它有所帮助。
我是这样做的(可能不是很优雅的解决方案)
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>
你可以看看这个问题。我发布了一个解决方案。
我有另一个很好的想法。子类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如果他们需要。
正如上面写的@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_parent
和SwipeRefresh
有wrap_content
。当列表中有项目时,不要忘记制作 text gone
。
我尝试过 UI hack,但没有成功,唯一有效的解决方案是设置适配器。传递空值确保该值不会为空。
NotificationListAdapter notificationListAdapter;
notificationListAdapter = new NotificationListAdapter(mContext,notificationResponse);
reCycleViewNotificationList.setAdapter(notificationListAdapter); // weather ListView or RecyclerView