Agregue margen sobre el elemento superior de ListView (y debajo del último) en Android

147

Esta es una pregunta bastante buena sobre el diseño de elementos en un ListView en Android.

Tengo una actividad con una barra de título en la parte superior y un ListView que ocupa el resto de la pantalla. Quiero que mi ListView aparezca con un relleno de 10dp a la izquierda, derecha y arriba, pero cuando desplace el ListView hacia arriba, quiero que cubra el relleno de 10dp superior antes de desaparecer debajo del borde desvaído. Del mismo modo, cuando se desplaza hacia la parte inferior, el último elemento de la lista debe aparecer con 10dp entre la parte inferior del último elemento de la lista y la parte inferior real de la pantalla (si se pregunta por qué, es porque hay una bonita imagen de fondo que quiero) asomando alrededor del ListView).

Intenté agregar relleno al ListView en sí, pero luego, al desplazar la lista, desaparece debajo del borde del relleno.

Soy de un fondo de desarrollo web, y la analogía sería agregar margen sobre el primer elemento de la lista (y debajo del último elemento de la lista).

Mick Byrne
fuente
especifique solo el margen izquierdo y derecho ... intente pegar su xml aquí, para que pueda ver la edición del problema: espere, quiere decir ... ¿Desea que se desplacen también el relleno superior e inferior?
Tek Yin
No puedo especificar el margen izquierdo y derecho: no hay 'margen' en el diseño de Android, solo relleno. Pero sí, quiero que se desplace el relleno superior e inferior, es una buena forma de describirlo.
Mick Byrne
Ya probé varios métodos, y aún fallé ... Tengo algunos trucos que hacer, pero será más difícil de hacer ... pones 2 objetos personalizados en el elemento de la lista en la primera y última posición ... y usas un adaptador personalizado para detectar el elemento y dibujarlo de manera diferente (altura estrecha y transparente)
Tek Yin
Sí ... eso es a lo que he estado pensando recurrir también. Pero hay todo tipo de complicaciones con eso, ya que luego tendré que establecer el color de fondo en los elementos de la lista, no en la vista, lo que significa que luego tendré que hackear manualmente algún efecto para mostrar cuando haya tocado cosas . Gracias por su ayuda de todos modos ...
Mick Byrne
Buenas noticias ... Tengo la solución ... puedes usar addHeaderView (View v) en ListActivity ... solo llama getListView(). addHeaderView(capView)y getListView(). addHeaderView(botView) asegúrate de que llamó antes de inicializar el contenido de la lista, por ejemplo. setListAdapter (adaptador);
Tek Yin

Respuestas:

397

Tu escribiste:

Intenté agregar relleno al ListView en sí, pero luego, al desplazar la lista, desaparece debajo del borde del relleno.

Establecer ListView's clipToPaddingatributo a false. Esto habilitará el relleno alrededor ListView y el desplazamiento hasta el final del diseño (y no solo hasta el borde del relleno).

Un ejemplo:

<ListView
    android:id="@+id/list_view"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:divider="@android:color/transparent"
    android:dividerHeight="10.0sp"
    android:padding="16dip"
    android:clipToPadding="false"/>

android:clipToPaddinges un atributo XML de ViewGroup, la clase base para diseños y contenedores de vistas.

La llamada al método relacionado es:

public void setClipToPadding (boolean clipToPadding)
Gunnar Karlsson
fuente
44
Además, esto se puede convertir en un estilo o tema a través de<item name="android:clipToPadding">false</item>
pjco
2
Oh, esto también se aplica a ScrollView
pjco
44
Un poco tarde para la discusión, pero tenga en cuenta que en dispositivos más antiguos (lo vi en algunos dispositivos 2.3.x), las vistas de elementos de la lista se reciclan demasiado pronto. Si bien la fase de dibujo sabe que puede dibujar allí, la fase de diseño no, por lo que cree que el elemento ya está fuera de la pantalla. Ver stackoverflow.com/questions/15915226/… .
Jeffrey Klardie
@JeffreyKlardie Me encuentro con el problema de que los artículos se reciclan demasiado pronto en un dispositivo antiguo e incluso hace que la barra de desplazamiento se redimensione sobre la marcha, lo que se ve realmente extraño. @pjco No estoy seguro de por qué, pero la configuración a clipToPaddingtravés de un estilo no me funciona, es como si no se aplicara. Aunque, si lo configuro directamente en ListView, funciona.
ForceMagic
55
No olvides android:scrollbarStyle="outsideOverlay"que la barra de desplazamiento también recorre todo el relleno
jfcartier
19
View padding = new View(this);
padding.setHeight(20); // Can only specify in pixels unfortunately. No DIP :-(

ListView myListView = (ListView) findViewById(R.id.my_list_view);

myListView.addHeaderView(padding);
myListView.addFooterView(padding);

myListView.setAdapter(myAdapter);

El ListView anterior tendrá un relleno de encabezado y pie de página de 20 píxeles.

Jake Wilson
fuente
44
¡Gracias por la respuesta! ¡¡Funciona genial!! Si desea poner altura en dp, puede hacerlo usando DisplayMetrics: float mDensity = getResources().getDisplayMetrics().density; int height = (int) (50 * mDensity + 0.5f); padding.setHeight(height);
Tony Ceralva
3
O mejor aún, obtenga dimens en dp en el nivel Java utilizando getResources (). GetDimensionPixelOffset (R.dimen.some_value);
greg7gkb
1
Realmente asombrado de la cantidad de cosas de Android que aprendo en StackOverflow en comparación con las que aprendo en el sitio de desarrolladores
TrueCoke
1
O incluso mejor(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics());
Eugen Pechanec
1
No hay un método "setHeight ()" para Ver en la API 23. En su lugar, podemos usar "setMinimumHeight ()".
KWA
10

Apéndice a la respuesta de @ Jakobud ...

Mi listView ya estaba haciendo uso de las android:divider/android:dividerHeightpropiedades para crear espacios transparentes entre los elementos de listView. Esto permitió que añada simplemente los android:headerDividersEnabledy las android:footerDividersEnabledpropiedades y establecer los puntos de vista de encabezado y pie de página para new View(Activity.this).

Ligera simplificación para casos en los que ya tiene divisores configurados en listView.

greg7gkb
fuente
1
Siempre que sea posible, recomendaría a cualquiera que use divisores en lugar de márgenes y rellenos de elementos. Gran respuesta
dzsonni
2

Mi solución usando a ListFragment, basada en las soluciones de @Jakobud y @ greg7gkb.

ListView listView = getListView();
listView.setDivider(null);
listView.setDividerHeight(getResources().getDimensionPixelSize(R.dimen.divider_height));
listView.setHeaderDividersEnabled(true);
listView.setFooterDividersEnabled(true);
View padding = new View(getActivity());
listView.addHeaderView(padding);
listView.addFooterView(padding);
hleinona
fuente
1

La respuesta de @Gunnar Karlsson es buena, pero tiene el problema de que las vistas de celda se reciclan prematuramente cuando están completamente detrás del relleno, pero aún no están completamente fuera de la pantalla. La configuración de clipToPadding = false es responsable de esto y puede o no repararse en una versión futura de Android. ( Al usar clipToPadding en ListView, los elementos se reciclan prematuramente )

Tengo una buena solución simple sin efectos secundarios:

  1. Agregue un diseño externo (lineal o relativo) a su cell_design.xml
  2. En este diseño externo, agregue relleno (es decir, 10dip) para crear un "margen" alrededor de toda la celda. (Nota: solo el relleno funcionará, no el margen en el diseño exterior)
  3. En el conjunto ListView android:dividerHeight="-10dip", lo contrario de lo que está alrededor de la celda

En comparación con la otra respuesta, no es necesario establecer el color del divisor. El relleno en las celdas superiores e inferiores estará presente, y el divisor negativo evitará divisores de doble altura en el medio.

James
fuente
"sin efectos secundarios" eso no es del todo cierto. Agregar otra capa en su jerarquía de vistas, especialmente en un elemento de vista de lista, significa degradar las actuaciones.
Teovald