android - recyclerview - swiperefreshlayout example
Android soporta v4 SwipeRefreshLayout problema de vista vacía (8)
SwipeRefresh no funciona después de configurar una vista vacía para listview que es el único hijo de un diseño SwipeRefresh. ¿Cómo resolver este problema?
Aquí está la solución: simplemente puede utilizar esta jerarquía de vistas:
<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>
Luego, en el código, simplemente llame:
_listView.setEmptyView(findViewById(android.R.id.empty));
Eso es.
Así es como hice esto (solución probablemente no muy elegante)
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();
}
}
diseño vacío
<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" />
diseño de lista
<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>
Como @Dinesh escrito anteriormente, he usado clickable="true"
como abajo con RecyclerView
vacío:
mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setClickable(true);
myText.setVisibility(View.VISIBLE);
diseño 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
tiene la altura match_parent
y SwipeRefresh
tiene wrap_content
. Cuando hay un elemento en la lista, no olvides hacer que el texto se haya gone
.
El problema para mí fue que cuando se veía la vista vacía, no se mostraba el círculo refrescante, aunque funcionaba el método refrescante. Para mi este código funcionó, espero que ayude.
el diseño 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>
el SwipeRefreshLayout personalizado:
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); } }
y en mi Fragmento, donde uso el diseño, solo configuro el deslizamiento para actualizar el diseño de esta manera:
mSwipeRefreshLayout.setListView(mListView);
La vista vacía de ListView se establece de esta manera:
TextView emptyView = (TextView) view.findViewById(R.id.empty_view); emptyView.setText("No data"); mListView.setEmptyView(emptyView);
Espero que ayude.
Puedes revisar este problema. Publiqué una solución de trabajo.
Solucioné este problema usando dos SwipeToRefreshLayouts.
- Uno para envolver el ListView
- El otro como un vacío.
Publiqué mi código en GitHub .
También tuve este problema, y lo resolví sin ningún código adicional en la actividad utilizando el diseño a continuación.
Si está utilizando un ListActivity
o ListFragment
se encarga de mostrar / ocultar la vista vacía, y la actualización funciona con una lista vacía y también con esta estructura de diseño.
No se necesitan hacks, todo está en SwipeRefreshLayout
, como debería ser.
<?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>
Espero que esto te ayude. Si es así, no olvides aceptar la respuesta.
Nota: este es un duplicado de mi respuesta a esta pregunta , pero esa pregunta es casi un duplicado de esta pregunta ... :)
ACTUALIZAR
Si SwipeRefreshLayout se activa demasiado pronto, puede implementar ListView.OnScroll con:
_refresher.Enabled = e.FirstVisibleItem == 0;
Esto desactiva la actualización hasta que se desplaza a la parte superior. Esto solo es necesario cuando se usa un ListView, el nuevo RecyclerView funciona como se esperaba.
Tengo otra idea que funciona bien. Subclase ListView y anule setAdapter () y setEmptyView () . setEmptyView solo debe almacenar la vista para usarla en la vista vacía, y setAdapter debe registrar un DataSetObserver que oculte / muestre la vista vacía sin alterar la visibilidad de la vista de lista. Es probable que desee utilizar un FrameLayout que contenga su SwipeToRefreshLayout y una vista vacía (como hermanos). A continuación, puede colocar la vista vacía en la parte superior / media / inferior, etc. con bastante facilidad utilizando la gravedad y la gravedad del diseño. También puedes usar un RelativeLayout pero no lo he intentado. Deseará anular el registro del dataSetObserver, creo que puede hacerlo en onDetachFromWindow como lo hice a continuación.
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);
}
}
}
Ejemplo de archivo de diseño:
<?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>
Si bien esto requiere un poco más de código que simplemente subclasificar ListView y alterar setVisibility para que no establezca la lista en GONE / HIDDEN, siento que esto no es tan fácil y aún permite al usuario configurar la lista en GONE / Hidden si necesitaban