Поддержка Android v4 SwipeRefreshLayout проблема с пустым представлением

SwipeRefresh не работает после установки пустого представления для listview, который является единственным дочерним элементом макета SwipeRefresh. Как решить эту проблему?

Solutions Collecting From Web of "Поддержка Android v4 SwipeRefreshLayout проблема с пустым представлением"

Вот решение: вы можете просто использовать эту иерархию представлений:

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

Вот и все.

Проблема для меня заключалась в том, что, когда пустой вид был видимым, освежающий круг не показывался, хотя метод освежения работал. Для меня этот код работал, надеюсь, это поможет.

  • Расположение 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); 

Я надеюсь, что это помогает.

У меня тоже была эта проблема, и я решил ее без какого-либо дополнительного кода в этом упражнении , используя макет ниже.

Если вы используете 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> 

Надеюсь, это вам поможет. Если да, не забудьте принять ответ.

Примечание: это дубликат моего ответа на этот вопрос , но этот вопрос в значительной степени дублирует этот вопрос … 🙂

ОБНОВИТЬ
Если SwipeRefreshLayout активирован слишком рано, вы можете реализовать ListView.OnScroll с помощью:

 _refresher.Enabled = e.FirstVisibleItem == 0; 

Это отключает обновление, пока вы не прокрутите вверх. Это необходимо только при использовании ListView, новый RecyclerView работает так, как ожидалось.

Вот как я сделал это (возможно, не очень элегантное решение)

 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> 

Вы можете проверить эту проблему. Я опубликовал решение для работы.

Android – SwipeRefreshLayout с пустым текстовым просмотром

Я исправил эту проблему, используя два SwipeToRefreshLayouts.

  • Один для упаковки ListView
  • Другой – пустой

Я отправил свой код на GitHub .

Как написал @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 . Когда в списке есть элемент, не забудьте оставить текст.

У меня есть другая идея, которая хорошо работает. Подкласс 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 Если они нужны.