SwipeRefresh не работает после установки пустого представления для listview, который является единственным дочерним элементом макета SwipeRefresh. Как решить эту проблему?
Поддержка Android v4 SwipeRefreshLayout проблема с пустым представлением
Ответ 1
Вот решение: Вы можете просто использовать эту иерархию представлений:
<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));
Что это.
Ответ 2
У меня тоже была эта проблема, и я решил без какого-либо дополнительного кода в действии, используя макет ниже.
Если вы используете ListActivity
или ListFragment
, он обрабатывает отображение/скрытие пустого представления для вас и обновляет работу с пустым списком также с этой структурой компоновки.
Никаких взломов не требуется, все в 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>
Надеюсь, это поможет вам. Если да, не забудьте принять ответ.
Примечание: это дубликат моего ответа на этот вопрос, но этот вопрос в значительной степени дублирует этот вопрос...:)
UPDATE
Если SwipeRefreshLayout активирован слишком рано, вы можете реализовать ListView.OnScroll с помощью:
_refresher.Enabled = e.FirstVisibleItem == 0;
Это отключает обновление до прокрутки вверх. Это необходимо только при использовании ListView, новый RecyclerView работает так, как ожидалось.
Ответ 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);
Надеюсь, это поможет.
Ответ 4
вот как я это сделал (возможно, не очень изящное решение)
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>
Ответ 5
Вы можете проверить эту проблему. Я опубликовал решение для работы.
Ответ 6
Я исправил эту проблему, используя два SwipeToRefreshLayouts.
- Один для упаковки ListView
- Другое как emptyView
Я разместил свой код на GitHub.
Ответ 7
Как написано выше @Dinesh, я использовал clickable="true"
, как показано ниже, с пустым 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
имеет высоту match_parent
и SwipeRefresh
имеет wrap_content
. Когда в списке есть элемент, не забудьте сделать текст gone
.
Ответ 8
У меня есть другая идея, которая хорошо работает. Подкласс 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, я чувствую, что это меньше взломать и по-прежнему позволяет пользователю установить список GONE/Hidden, если нужно.
Ответ 9
Я попытался взломать пользовательский интерфейс, но это не сработало, единственное решение - установить адаптер. передайте пустое значение, убедитесь, что оно не будет нулевым.
NotificationListAdapter notificationListAdapter;
notificationListAdapter = new NotificationListAdapter(mContext,notificationResponse);
reCycleViewNotificationList.setAdapter(notificationListAdapter); // weather ListView or RecyclerView