studio llenar example custom como arrayadapter agregar activity android android-listview

llenar - listview android example



Android-SwipeRefreshLayout con texto vacĂ­o (14)

¿Por qué no envolver todo dentro de SwipeRefreshLayout?

<android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipe" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal"/> <RelativeLayout android:id="@android:id/empty" android:layout_width="match_parent" android:layout_height="match_parent" > ... </RelativeLayout> </LinearLayout> </android.support.v4.widget.SwipeRefreshLayout>

Implementé SwipeRefreshLayout en mi aplicación, pero solo puede contener un elemento secundario directo, que debería ser la vista de lista. Estoy intentando descubrir cómo agregar una vista de texto vacía al siguiente archivo XML que funciona:

<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/swipe_container" android:layout_width="match_parent" android:layout_height="match_parent" > <ListView android:id="@+id/listViewConversation" android:layout_width="fill_parent" android:layout_height="fill_parent" android:dividerHeight="1dp" /> </android.support.v4.widget.SwipeRefreshLayout>

Envolverlo en un diseño lineal / relativo lo hace defectuoso porque la vista de lista siempre se actualizará cuando desee deslizar hacia atrás la vista de lista. Una forma en que puedo pensar es haciendo esto programáticamente, pero supongo que esa no es la mejor opción.

Puedes aprender cómo implementarlo usando este tutorial: Desliza para actualizar GUÍA

Así que, básicamente, todo funciona bien, pero me gustaría agregar una vista vacía que muestra un mensaje cuando la vista de lista está vacía.


Coloque SwipeRefreshLayout en un FrameLayout y otras vistas detrás de él.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:id="@+id/your_message_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="No result"/> </LinearLayout> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipe_container" android:layout_width="match_parent" android:layout_height="match_parent" > <ListView android:id="@+id/your_list_view" android:layout_width="match_parent" android:layout_height="wrap_content"> </ListView> </android.support.v4.widget.SwipeRefreshLayout> </FrameLayout>


Como mencioné here , he hecho esto para RecyclerView :

He utilizado clickable="true" como a continuación 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 height match_parent y SwipeRefresh tiene wrap_content . Cuando hay un elemento en la lista, no olvides dejar el texto.


En realidad, lo único que te falta es tener ese TextView vacío envuelto con un contenedor desplazable , por ejemplo, ScrollView . Para más detalles, eche un vistazo al método SwipeRefreshLayout.canChildScrollUp() y su uso.

De cualquier manera, volviendo al tema. Aquí hay una implementación exitosa:

activity_some.xml

<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/swipe_container" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:measureAllChildren="true"> <WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" /> <include layout="@layout/empty" /> </FrameLayout> </android.support.v4.widget.SwipeRefreshLayout>

Donde su empty.xml es básicamente cualquier cosa que desee envolver con ScrollView .

empty.xml

<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/empty" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <TextView android:text="Nothing here..." android:layout_width="wrap_content" android:layout_height="wrap_content" /> </ScrollView>

Ahora, para deshacerte del famoso problema SwipeRefreshLayout refresh-only-when-at-the-top, alternar el SwipeRefreshLayout cuando sea necesario (Fragmento-específico):

private ViewTreeObserver.OnScrollChangedListener mOnScrollChangedListener; @Override public void onStart() { super.onStart(); mOnScrollChangedListener = new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { int scrollY = mWebView.getScrollY(); if (scrollY == 0) swipeLayout.setEnabled(true); else swipeLayout.setEnabled(false); } }; swipeLayout.getViewTreeObserver().addOnScrollChangedListener(mOnScrollChangedListener); } @Override public void onStop() { swipeLayout.getViewTreeObserver().removeOnScrollChangedListener(mOnScrollChangedListener); super.onStop(); }

¡Eso es! ¡Espero eso ayude! ;)

Por cierto, ¿por qué usaría SwipeRefreshLayout con FrameLayout esta manera? Porque de esta manera puedes hacer animaciones de transición sin problemas, como efectos de fundido cruzado , y cualquiera de tus vistas de estado puede deslizarte (en caso de que desees un mecanismo unificado de búsqueda / actualización / reintento ).


Este fue un problema muy frustrante para mí, pero después de unas pocas horas con el intento y el fracaso, se me ocurrió esta solución.

Con esto puedo actualizar incluso con la vista vacía visible (y también con RecyclerView)

En mi archivo de diseño tengo esta estructura:

SwipeRefreshLayout FrameLayout RecyclerView my_empty_layout // Doesnt have to be ScrollView it can be whatever ViewGroup you want, I used LinearLayout with a single TextView child

En codigo:

... adapter.notifyDataSetChanged() if (adapter.getItemCount() == 0) { recyclerView.setVisibility(View.GONE); emptyView.setVisibility(View.VISIBLE); } else { recyclerView.setVisibility(View.VISIBLE); emptyView.setVisibility(View.GONE); }


Esto es lo que hice: deshabilité el deslizamiento para actualizar, a menos que mi lista esté activa.

mBookedProductsListView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView absListView, int i) { } @Override public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (firstVisibleItem == 0) mSwipeRefreshLayout.setEnabled(true); else mSwipeRefreshLayout.setEnabled(false); } });

Mi Xml:

<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/swipeRefreshLayout" android:layout_width="match_parent" android:layout_height="match_parent" > <RelativeLayout android:id="@+id/productListLL" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > <EditText android:id="@+id/search" android:layout_width="match_parent" android:layout_height="40dp" android:layout_alignParentTop="true" android:background="#a4aeb8" android:drawableRight="@drawable/search_icon" android:paddingRight="15dp" android:textColor="@android:color/white" android:paddingLeft="15dp" android:hint="Rechercher" android:textColorHint="@android:color/white" android:inputType="textCapWords|textNoSuggestions" /> <include android:layout_width="match_parent" android:layout_height="wrap_content" layout="@layout/filter_by_categories_buttons" android:id="@+id/categoriesTree" android:layout_below="@id/search" /> <ListView android:id="@+id/productListLV" android:layout_width="match_parent" android:layout_height="match_parent" android:divider="@drawable/product_listview_divider" android:dividerHeight="1dp" android:scrollbars="none" android:overScrollMode="never" android:choiceMode="multipleChoiceModal" android:background="#e7eaef" android:visibility="gone" android:layout_below="@id/categoriesTree" /> </RelativeLayout> </android.support.v4.widget.SwipeRefreshLayout>

Funciona de maravilla.


Esto funcionó para mí

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/lighter_white"> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeContainer" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:background="@color/silver" android:layout_marginTop="10dp" android:divider="@android:color/transparent" android:dividerHeight="8dp" android:padding="4dp"/> </android.support.v4.widget.SwipeRefreshLayout> <TextView android:id="@+id/empty" android:text="@string/strNoRecordsFound" android:layout_width="match_parent" android:layout_height="match_parent" android:textColor="@android:color/black" android:alpha="0.5" android:gravity="center"> </TextView> </FrameLayout>


He intentado lo siguiente. Tanto en la vista vacía como en el caso de una lista, el deslizamiento refrescará los datos, también fastscroll está funcionando bien sin ningún cambio de código requerido en la actividad. He puesto emptyview antes de la vista de lista y marqué su visibilidad para desaparecer. y listview se pone después de eso dentro del bloque SwipeToRefresh. Código de muestra -

<FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/tv_empty_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="32dp" android:gravity="center_horizontal" android:text="No item found" android:visibility="gone"/> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipe" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/lv_product" android:layout_width="match_parent" android:layout_height="match_parent" /> </android.support.v4.widget.SwipeRefreshLayout> </FrameLayout>


Me encontré con el mismo problema. Es molesto que SwipeRefreshLayout solo tenga un elemento secundario de AdpaterView .

Si se establece una vista vacía para un AdpaterView , se establecerá como oculta si no hay datos disponibles. Sin embargo, SwipeRefreshLayout necesita un AdpaterView para funcionar. Por lo tanto, extiendo AdpaterView para que se muestre aún, incluso si está vacío.

@Override public void setVisibility(int visibility) { if (visibility == View.GONE && getCount() == 0) { return; } super.setVisibility(visibility); }

Quizás también deba establecer el fondo de la vista del adaptador como transparente. Pero en mi caso, no es necesario, ya que la vista vacía es un simple TextView .


No hay necesidad de ninguna solución.

Simplemente puede usar esta jerarquía de vista:

<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 código, solo llama:

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

Eso es.

EDITAR: si deseas poder deslizar para actualizar incluso cuando se muestra la vista vacía, deberás evitar de alguna manera ocultar el ListView, por lo que podrías usar un ListView personalizado que tenga esta función dentro:

@Override public void setVisibility(final int visibility) { if(visibility!=View.GONE||getCount()!=0) super.setVisibility(visibility); }

Junto con la solución que escribí, se muestra el deslizamiento para actualizar, independientemente de la cantidad de elementos que muestre.

Por supuesto, si realmente desea ocultar ListView, debe cambiar el código. Tal vez agregue "setVisibilityForReal (...)" :)


No me gustó la limitación a un solo niño. Además, la implementación actual de SwipeRefreshLayout tiene un manejo "mágico" codificado para ScrollView, ListView y GridView que se activan solo si la vista es el elemento secundario directo de su propia vista.

Dicho esto, la buena noticia es que es de código abierto, por lo que puede copiar el código y adaptarse a sus necesidades o puede hacer lo que hice:

Utilice dos DIFERENTES SwipeRefreshLayout, uno para la vista Vacía y otro para el ListView.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.tobrun.example.swipetorefresh.MainActivity"> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefreshLayout_listView" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="wrap_content" /> </android.support.v4.widget.SwipeRefreshLayout> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefreshLayout_emptyView" android:layout_width="match_parent" android:layout_height="match_parent"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <TextView android:id="@+id/emptyView" android:text="@string/empty" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" /> </ScrollView> </android.support.v4.widget.SwipeRefreshLayout> </FrameLayout>

Luego dígale a su vista de lista que la vista de lista vacía es el diseño de actualización de barrido de la vista vacía.

Ahora la vista de lista ocultará automáticamente el diseño de actualización vacío cuando tenga datos y se mostrarán cuando la lista esté vacía.

El diseño de actualización de deslizamiento de la lista no debería recibir eventos táctiles porque la lista está oculta.

Buena suerte.


Otra opción que funciona bien en caso de que su vista vacía no necesite ninguna interacción. Por ejemplo, es una simple vista de texto que dice "No hay datos aquí".

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/emptyView" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:visibility="visible" android:layout_centerInParent="true" android:text="@string/no_earnable_available" android:textSize="18dp" android:textColor="@color/black" android:background="@color/white" /> <some.app.RecyclerViewSwipeToRefreshLayout android:id="@+id/swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingTop="4dp" android:background="@android:color/transparent" app:layout_behavior="@string/appbar_scrolling_view_behavior" > <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" /> </some.app.RecyclerViewSwipeToRefreshLayout> </RelativeLayout>

Esto pone la vista vacía detrás de SwipeToRefreshLayout que es transparente y que contiene también un RecyclerView transparente.

Luego, en el código, en el lugar donde agrega los elementos al adaptador de vista de reciclador, verifica si el adaptador está vacío y, de ser así, establece la visibilidad de la vista vacía en "visible". Y viceversa.

El truco es que la vista está detrás de la vista de reciclador transparente, lo que significa que la vista de reciclador y su elemento principal, SwipeToRefreshLayout, manejarán el desplazamiento cuando no haya elementos en la recicladora. La vista vacía de atrás ni siquiera se tocará, por lo que SwypeTorefreshLayout consumirá el evento táctil.

El RecyclerSwipeTorefreshLayout personalizado debe manejar el método canChildScrollUp de la siguiente manera

@Override public boolean canChildScrollUp() { if (recycler == null) throw new IllegalArgumentException("recycler not set!"); else if (recycler.getAdapter().getItemCount() == 0){ // this check could be done in a more optimised way by setting a flag from the same place where you change the visibility of the empty view return super.canChildScrollUp(); } else { RecyclerView.LayoutManager layoutManager = recycler.getLayoutManager(); if (layoutManager instanceof LinearLayoutManager) { return ((LinearLayoutManager) recycler.getLayoutManager()).findFirstVisibleItemPosition() != 0 || (((LinearLayoutManager) recycler.getLayoutManager()).findFirstVisibleItemPosition() == 0 && recycler.getChildAt(0) != null && recycler.getChildAt(0).getY() < 0); //...

Esto hará el truco.

ACTUALIZACIÓN: por supuesto, la vista del reciclador no tiene que ser transparente todo el tiempo. Puede actualizar la transparencia para que esté activa solo cuando el adaptador esté vacío.

¡Aclamaciones!


Probablemente tarde, pero si todavía te enfrentas a este problema, ¡aquí está la solución limpia! No es necesario crear otro SwipeRefreshLayout .

envolver la empty view en un ScrollView . Pegue AdapterView y ScrollView en un ViewGroup y ViewGroup en SwipeRefreshLayout

Muestra:

<android.support.v4.widget.SwipeRefreshLayout android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:layout_width="match_parent" android:layout_height="match_parent" /> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="250dp" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" /> </ScrollView> </FrameLayout> </android.support.v4.widget.SwipeRefreshLayout>

EDITAR

Aquí hay una manera mucho más simple.

verifica si tu lista es empática. Si es así, hazlo invisible. Muestra:

if(lst.size() > 0) { mRecyclerView.setVisibility(View.VISIBLE); //set adapter }else { mRecyclerView.setVisibility(View.INVISIBLE); findViewById(R.id.txtNodata).setVisibility(View.VISIBLE); }

esto hará que mRecyclerView siga allí y todos los golpes funcionen bien ahora incluso si no hay datos.


Según algunas respuestas aquí y el código fuente de SwipeRefreshLayout, he subclasificado la vista para manejar específicamente tener un RecyclerView (o ListView) y también una vista "vacía" dentro de un contenedor que es el elemento secundario.

Espera un diseño como

<SwipeRefreshLayoutWithEmpty ...> <FrameLayout ...> <TextView android:text="List is Empty" ...> <RecyclerView ...> </FrameLayout> </SwipeRefreshLayoutWithEmpty>

El código es:

public class SwipeRefreshLayoutWithEmpty extends SwipeRefreshLayout { private ViewGroup container; public SwipeRefreshLayoutWithEmpty(Context context) { super(context); } public SwipeRefreshLayoutWithEmpty(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean canChildScrollUp() { // The swipe refresh layout has 2 children; the circle refresh indicator // and the view container. The container is needed here ViewGroup container = getContainer(); if (container == null) { return false; } // The container has 2 children; the empty view and the scrollable view. // Use whichever one is visible and test that it can scroll View view = container.getChildAt(0); if (view.getVisibility() != View.VISIBLE) { view = container.getChildAt(1); } return ViewCompat.canScrollVertically(view, -1); } private ViewGroup getContainer() { // Cache this view if (container != null) { return container; } // The container may not be the first view. Need to iterate to find it for (int i=0; i<getChildCount(); i++) { if (getChildAt(i) instanceof ViewGroup) { container = (ViewGroup) getChildAt(i); if (container.getChildCount() != 2) { throw new RuntimeException("Container must have an empty view and content view"); } break; } } if (container == null) { throw new RuntimeException("Container view not found"); } return container; } }

Completo: https://gist.github.com/grennis/16cb2b0c7f798418284dd2d754499b43