ListView est en fait déjà capable de se mesurer pour être suffisamment grand pour afficher tous les éléments, mais il ne le fait pas lorsque vous spécifiez simplement wrap_content (MeasureSpec.UNSPECIFIED). Il le fera lorsqu'il recevra une hauteur avec MeasureSpec.AT_MOST. Avec ces connaissances, vous pouvez créer une sous-classe très simple pour résoudre ce problème qui fonctionne bien mieux que toutes les solutions publiées ci-dessus. Vous devez toujours utiliser wrap_content avec cette sous-classe.
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 manipulation de heightMeasureSpec pour être AT_MOST avec une très grande taille (Integer.MAX_VALUE >> 4) oblige le ListView à mesurer tous ses enfants jusqu'à la hauteur donnée (très grande) et à définir sa hauteur en conséquence.
Cela fonctionne mieux que les autres solutions pour plusieurs raisons:
- Il mesure tout correctement (rembourrage, séparateurs)
- Il mesure le ListView pendant la passe de mesure
- En raison de # 2, il gère correctement les changements de largeur ou de nombre d'articles sans code supplémentaire
À la baisse, vous pourriez faire valoir que cela dépend de comportements non documentés dans le SDK qui pourraient changer. D'un autre côté, vous pourriez affirmer que c'est ainsi que wrap_content devrait vraiment fonctionner avec ListView et que le comportement actuel de wrap_content est simplement rompu.
Si vous craignez que le comportement puisse changer à l'avenir, vous devez simplement copier la fonction onMeasure et les fonctions connexes à partir de ListView.java et dans votre propre sous-classe, puis faire également le chemin AT_MOST via onMeasure pour UNSPECIFIED.
Soit dit en passant, je pense que c'est une approche parfaitement valable lorsque vous travaillez avec un petit nombre d'éléments de liste. Il peut être inefficace par rapport à LinearLayout, mais lorsque le nombre d'éléments est petit, l'utilisation de LinearLayout est une optimisation inutile et donc une complexité inutile.