ListView ya es capaz de medirse para ser lo suficientemente alto como para mostrar todos los elementos, pero no hace esto cuando simplemente especifica wrap_content (MeasureSpec.UNSPECIFIED). Lo hará cuando tenga una altura con MeasureSpec.AT_MOST. Con este conocimiento, puede crear una subclase muy simple para resolver este problema que funciona mucho mejor que cualquiera de las soluciones publicadas anteriormente. Aún debe usar wrap_content con esta subclase.
public class ListViewForEmbeddingInScrollView extends ListView {
public ListViewForEmbeddingInScrollView(Context context) {
super(context);
}
public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 4, MeasureSpec.AT_MOST));
}
}
La manipulación de heightMeasureSpec para que sea AT_MOST con un tamaño muy grande (Integer.MAX_VALUE >> 4) hace que ListView mida a todos sus hijos hasta la altura dada (muy grande) y establezca su altura en consecuencia.
Esto funciona mejor que las otras soluciones por algunas razones:
- Mide todo correctamente (relleno, divisores)
- Mide el ListView durante el paso de medida
- Debido al n. ° 2, maneja los cambios en el ancho o el número de elementos correctamente sin ningún código adicional
En el lado negativo, podría argumentar que hacer esto depende de un comportamiento indocumentado en el SDK que podría cambiar. Por otro lado, podría argumentar que así es como realmente debería funcionar wrap_content con ListView y que el comportamiento actual de wrap_content simplemente está roto.
Si le preocupa que el comportamiento pueda cambiar en el futuro, simplemente copie la función onMeasure y las funciones relacionadas de ListView.java y en su propia subclase, luego haga que la ruta AT_MOST a través de onMeasure se ejecute también para UNSPECIFIED.
Por cierto, creo que este es un enfoque perfectamente válido cuando trabajas con un pequeño número de elementos de la lista. Puede ser ineficiente en comparación con LinearLayout, pero cuando el número de elementos es pequeño, usar LinearLayout es una optimización innecesaria y, por lo tanto, una complejidad innecesaria.