¿Cómo puedo poner un ListView en un ScrollView sin colapsar?

He buscado soluciones para este problema, y ​​la única respuesta que puedo encontrar parece ser ” no coloque un ListView en un ScrollView “. Todavía tengo que ver una explicación real de por qué . La única razón por la que parece que puedo encontrar es que Google no cree que deba querer hacer eso. Bueno, sí, así que lo hice.

Entonces la pregunta es, ¿cómo se puede colocar un ListView en un ScrollView sin colapsar a su altura mínima?

Usar un ListView para hacer que no se desplace es extremadamente costoso y va en contra de todo el propósito de ListView . NO deberías hacer esto. Solo use LinearLayout en LinearLayout lugar.

Aquí está mi solución. Soy bastante nuevo en la plataforma de Android, y estoy seguro de que esto es un poco hackish, especialmente en la parte sobre llamar .Measure directamente, y configurar la propiedad LayoutParams.height directamente, pero funciona.

Todo lo que tienes que hacer es llamar a Utility.setListViewHeightBasedOnChildren(yourListView) y se cambiará el tamaño para acomodar exactamente la altura de sus elementos.

 public class Utility { public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { // pre-condition return; } int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom(); for (int i = 0; i < listAdapter.getCount(); i++) { View listItem = listAdapter.getView(i, null, listView); if (listItem instanceof ViewGroup) { listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); } listItem.measure(0, 0); totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); } } 

Esto definitivamente funcionará …………
Solo tiene que reemplazar su en el archivo XML de diseño con este Custom ScrollView como

 package com.tmd.utils; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.widget.ScrollView; public class VerticalScrollview extends ScrollView{ public VerticalScrollview(Context context) { super(context); } public VerticalScrollview(Context context, AttributeSet attrs) { super(context, attrs); } public VerticalScrollview(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.i("VerticalScrollview", "onInterceptTouchEvent: DOWN super false" ); super.onTouchEvent(ev); break; case MotionEvent.ACTION_MOVE: return false; // redirect MotionEvents to ourself case MotionEvent.ACTION_CANCEL: Log.i("VerticalScrollview", "onInterceptTouchEvent: CANCEL super false" ); super.onTouchEvent(ev); break; case MotionEvent.ACTION_UP: Log.i("VerticalScrollview", "onInterceptTouchEvent: UP super false" ); return false; default: Log.i("VerticalScrollview", "onInterceptTouchEvent: " + action ); break; } return false; } @Override public boolean onTouchEvent(MotionEvent ev) { super.onTouchEvent(ev); Log.i("VerticalScrollview", "onTouchEvent. action: " + ev.getAction() ); return true; } } 

Insistimos en poner ListView dentro de ScrollView , podemos usar ListView como ScrollView . Las cosas que tienen que estar en ListView se pueden poner dentro de ListView . Se pueden agregar otros diseños en la parte superior e inferior de ListView agregando diseños al encabezado y pie de página de ListView . Entonces todo ListView te dará una experiencia de desplazamiento.

Hay muchas situaciones en las que tiene mucho sentido tener ListView en un ScrollView.

Aquí está el código basado en la sugerencia de DougW … funciona en un fragmento, requiere menos memoria.

 public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { return; } int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST); int totalHeight = 0; View view = null; for (int i = 0; i < listAdapter.getCount(); i++) { view = listAdapter.getView(i, view, listView); if (i == 0) { view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, LayoutParams.WRAP_CONTENT)); } view.measure(desiredWidth, MeasureSpec.UNSPECIFIED); totalHeight += view.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); listView.requestLayout(); } 

llame a setListViewHeightBasedOnChildren (vista de lista) en cada vista de lista incrustada.

ListView ya es capaz de medirse para que sea lo suficientemente alto como para mostrar todos los elementos, pero no lo hace cuando simplemente especifica wrap_content (MeasureSpec.UNSPECIFIED). Hará esto cuando se le dé 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. Debería seguir usando 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)); } } 

Manipular el heightMeasureSpec para que sea AT_MOST con un tamaño muy grande (Integer.MAX_VALUE >> 4) hace que el ListView mida todos sus hijos hasta la altura dada (muy grande) y establece su altura en consecuencia.

Esto funciona mejor que las otras soluciones por algunas razones:

  1. Mide todo correctamente (relleno, divisores)
  2. Mide el ListView durante el paso de medida
  3. Debido al # 2, maneja los cambios en el ancho o la cantidad de elementos correctamente sin ningún código adicional

En el lado negativo, podría argumentar que hacer esto depende del comportamiento indocumentado en el SDK que podría cambiar. Por otro lado, podría argumentar que así es como wrap_content debería funcionar realmente con ListView y que el comportamiento actual de wrap_content simplemente se rompe.

Si le preocupa que el comportamiento pueda cambiar en el futuro, simplemente copie la función onMeasure y las funciones relacionadas fuera de ListView.java y en su propia subclase, luego haga que la ruta AT_MOST a través de Measure 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 ineficaz 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.

Hay una configuración incorporada para eso. En el ScrollView:

 android:fillViewport="true" 

En Java,

 mScrollView.setFillViewport(true); 

Romain Guy lo explica en profundidad aquí: http://www.curious-creature.org/2010/08/15/scrollviews-handy-trick/

No podríamos usar dos desplazamientos simultáneos. Tendremos la longitud total de ListView y ampliaremos la vista de lista con la altura total. Luego podemos agregar ListView en ScrollView directamente o usando LinearLayout porque ScrollView tiene directamente un elemento secundario. copie el método setListViewHeightBasedOnChildren (lv) en su código y expanda listview, luego puede usar listview dentro de scrollview. \ layout xml file

            

método onCreate en la clase de actividad:

  import java.util.ArrayList; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListAdapter; import android.widget.ListView; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.listview_inside_scrollview); ListView list_first=(ListView) findViewById(R.id.first_listview); ListView list_second=(ListView) findViewById(R.id.secondList); ArrayList list=new ArrayList(); for(int x=0;x<30;x++) { list.add("Item "+x); } ArrayAdapter adapter=new ArrayAdapter(getApplicationContext(), android.R.layout.simple_list_item_1,list); list_first.setAdapter(adapter); setListViewHeightBasedOnChildren(list_first); list_second.setAdapter(adapter); setListViewHeightBasedOnChildren(list_second); } public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { // pre-condition return; } int totalHeight = 0; for (int i = 0; i < listAdapter.getCount(); i++) { View listItem = listAdapter.getView(i, null, listView); listItem.measure(0, 0); totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); } 

Crea un ListView personalizado que no es desplazable

 public class NonScrollListView extends ListView { public NonScrollListView(Context context) { super(context); } public NonScrollListView(Context context, AttributeSet attrs) { super(context, attrs); } public NonScrollListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec( Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom); ViewGroup.LayoutParams params = getLayoutParams(); params.height = getMeasuredHeight(); } } 

En su archivo de recursos de diseño

         

En archivo Java

Cree un objeto de su vista personalizada en lugar de ListView como: NonScrollListView non_scroll_list = (NonScrollListView) findViewById (R.id.lv_nonscroll_list);

Esta es una combinación de las respuestas de DougW, Good Guy Greg y Paul. Descubrí que todo era necesario cuando intentaba usar esto con un adaptador de vista de lista personalizado y elementos de lista no estándar; de lo contrario, la vista de lista bloqueaba la aplicación (también se bloqueó con la respuesta de Nex):

 public void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { return; } int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom(); for (int i = 0; i < listAdapter.getCount(); i++) { View listItem = listAdapter.getView(i, null, listView); if (listItem instanceof ViewGroup) listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); listItem.measure(0, 0); totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); } 

Convertí la Utility @ DougW en C # (utilizada en Xamarin). Lo siguiente funciona bien para artículos de altura fija en la lista, y va a ser mayormente bueno, o al menos un buen comienzo, si solo algunos de los artículos son un poco más grandes que el artículo estándar.

 // You will need to put this Utility class into a code file including various // libraries, I found that I needed at least System, Linq, Android.Views and // Android.Widget. using System; using System.Linq; using Android.Views; using Android.Widget; namespace UtilityNamespace // whatever you like, obviously! { public class Utility { public static void setListViewHeightBasedOnChildren (ListView listView) { if (listView.Adapter == null) { // pre-condition return; } int totalHeight = listView.PaddingTop + listView.PaddingBottom; for (int i = 0; i < listView.Count; i++) { View listItem = listView.Adapter.GetView (i, null, listView); if (listItem.GetType () == typeof(ViewGroup)) { listItem.LayoutParameters = new LinearLayout.LayoutParams (ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent); } listItem.Measure (0, 0); totalHeight += listItem.MeasuredHeight; } listView.LayoutParameters.Height = totalHeight + (listView.DividerHeight * (listView.Count - 1)); } } } 

Gracias @DougW, esto me sacó de aprietos cuando tuve que trabajar con OtherPeople'sCode. 🙂

No debe poner un ListView en un ScrollView porque un ListView ya es un ScrollView. Así que sería como poner un ScrollView en un ScrollView.

¿Qué está tratando de lograr?

hey, tuve un problema similar Quería mostrar una vista de lista que no se desplazara y encontré que la manipulación de los parámetros funcionaba pero era ineficiente y se comportaría de manera diferente en diferentes dispositivos … como resultado, esta es una parte de mi código de progtwigción que realmente hace esto de manera muy eficiente .

 db = new dbhelper(this); cursor = db.dbCursor(); int count = cursor.getCount(); if (count > 0) { LinearLayout linearLayout = (LinearLayout) findViewById(R.id.layoutId); startManagingCursor(YOUR_CURSOR); YOUR_ADAPTER(**or SimpleCursorAdapter **) adapter = new YOUR_ADAPTER(this, R.layout.itemLayout, cursor, arrayOrWhatever, R.id.textViewId, this.getApplication()); int i; for (i = 0; i < count; i++){ View listItem = adapter.getView(i,null,null); linearLayout.addView(listItem); } } 

Nota: si usa esto, notifyDataSetChanged(); no funcionará según lo previsto ya que las vistas no se volverán a dibujar. Haga esto si necesita un trabajo alrededor

 adapter.registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { super.onChanged(); removeAndRedrawViews(); } }); 

Hay dos problemas al usar un ListView dentro de ScrollView.

1- ListView debe expandirse completamente a la altura de sus hijos. este ListView resolver esto:

 public class ListViewExpanded extends ListView { public ListViewExpanded(Context context, AttributeSet attrs) { super(context, attrs); setDividerHeight(0); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST)); } } 

La altura del divisor debe ser 0; en cambio, use relleno en filas.

2- ListView consume eventos táctiles, por lo que ScrollView no se puede desplazar como de costumbre. Este ScrollView resuelve este problema:

 public class ScrollViewInterceptor extends ScrollView { float startY; public ScrollViewInterceptor(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent e) { onTouchEvent(e); if (e.getAction() == MotionEvent.ACTION_DOWN) startY = e.getY(); return (e.getAction() == MotionEvent.ACTION_MOVE) && (Math.abs(startY - e.getY()) > 50); } } 

¡Esta es la mejor manera que encontré para hacer el truco!

Esto es lo único que funcionó para mí:

en Lollipop en adelante puedes usar

 yourtListView.setNestedScrollingEnabled(true); 

Esto habilita o deshabilita el desplazamiento nested para esta vista, si necesita compatibilidad con versiones anteriores del sistema operativo, tendrá que usar RecyclerView.

Gracias al código de Vinay, aquí está mi código para cuando no se puede tener una vista de lista dentro de una vista de desplazamiento, pero se necesita algo como eso

 LayoutInflater li = LayoutInflater.from(this); RelativeLayout parent = (RelativeLayout) this.findViewById(R.id.relativeLayoutCliente); int recent = 0; for(Contatto contatto : contatti) { View inflated_layout = li.inflate(R.layout.header_listview_contatti, layout, false); inflated_layout.setId(contatto.getId()); ((TextView)inflated_layout.findViewById(R.id.textViewDescrizione)).setText(contatto.getDescrizione()); ((TextView)inflated_layout.findViewById(R.id.textViewIndirizzo)).setText(contatto.getIndirizzo()); ((TextView)inflated_layout.findViewById(R.id.textViewTelefono)).setText(contatto.getTelefono()); ((TextView)inflated_layout.findViewById(R.id.textViewMobile)).setText(contatto.getMobile()); ((TextView)inflated_layout.findViewById(R.id.textViewFax)).setText(contatto.getFax()); ((TextView)inflated_layout.findViewById(R.id.textViewEmail)).setText(contatto.getEmail()); RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); if (recent == 0) { relativeParams.addRule(RelativeLayout.BELOW, R.id.headerListViewContatti); } else { relativeParams.addRule(RelativeLayout.BELOW, recent); } recent = inflated_layout.getId(); inflated_layout.setLayoutParams(relativeParams); //inflated_layout.setLayoutParams( new RelativeLayout.LayoutParams(source)); parent.addView(inflated_layout); } 

el relativeLayout permanece dentro de un ScrollView para que todo se pueda desplazar 🙂

Aquí hay una pequeña modificación en la respuesta de @djunod que necesito para que funcione perfectamente:

 public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if(listAdapter == null) return; if(listAdapter.getCount() <= 1) return; int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST); int totalHeight = 0; View view = null; for(int i = 0; i < listAdapter.getCount(); i++) { view = listAdapter.getView(i, view, listView); view.measure(desiredWidth, MeasureSpec.UNSPECIFIED); totalHeight += view.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); listView.requestLayout(); } 

intenta esto, esto funciona para mí, olvidé dónde lo encontré, en algún lugar en desbordamiento de stack, no estoy aquí para explicar por qué no funciona, pero esta es la respuesta :).

  final ListView AturIsiPulsaDataIsiPulsa = (ListView) findViewById(R.id.listAturIsiPulsaDataIsiPulsa); AturIsiPulsaDataIsiPulsa.setOnTouchListener(new ListView.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: // Disallow ScrollView to intercept touch events. v.getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_UP: // Allow ScrollView to intercept touch events. v.getParent().requestDisallowInterceptTouchEvent(false); break; } // Handle ListView touch events. v.onTouchEvent(event); return true; } }); AturIsiPulsaDataIsiPulsa.setClickable(true); AturIsiPulsaDataIsiPulsa.setAdapter(AturIsiPulsaDataIsiPulsaAdapter); 

EDIT!, Finalmente descubrí dónde obtuve el código. aquí ! : ListView dentro de ScrollView no se desplaza en Android

Aunque los métodos sugeridos de setListViewHeightBasedOnChildren () funcionan en la mayoría de los casos, en algunos casos, especialmente con muchos elementos, noté que los últimos elementos no se muestran. Así que decidí imitar una versión simple del comportamiento de ListView para reutilizar cualquier código de adaptador, aquí está la alternativa de ListView:

 import android.content.Context; import android.database.DataSetObserver; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.LinearLayout; import android.widget.ListAdapter; public class StretchedListView extends LinearLayout { private final DataSetObserver dataSetObserver; private ListAdapter adapter; private OnItemClickListener onItemClickListener; public StretchedListView(Context context, AttributeSet attrs) { super(context, attrs); setOrientation(LinearLayout.VERTICAL); this.dataSetObserver = new DataSetObserver() { @Override public void onChanged() { syncDataFromAdapter(); super.onChanged(); } @Override public void onInvalidated() { syncDataFromAdapter(); super.onInvalidated(); } }; } public void setAdapter(ListAdapter adapter) { ensureDataSetObserverIsUnregistered(); this.adapter = adapter; if (this.adapter != null) { this.adapter.registerDataSetObserver(dataSetObserver); } syncDataFromAdapter(); } protected void ensureDataSetObserverIsUnregistered() { if (this.adapter != null) { this.adapter.unregisterDataSetObserver(dataSetObserver); } } public Object getItemAtPosition(int position) { return adapter != null ? adapter.getItem(position) : null; } public void setSelection(int i) { getChildAt(i).setSelected(true); } public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } public ListAdapter getAdapter() { return adapter; } public int getCount() { return adapter != null ? adapter.getCount() : 0; } private void syncDataFromAdapter() { removeAllViews(); if (adapter != null) { int count = adapter.getCount(); for (int i = 0; i < count; i++) { View view = adapter.getView(i, null, this); boolean enabled = adapter.isEnabled(i); if (enabled) { final int position = i; final long id = adapter.getItemId(position); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (onItemClickListener != null) { onItemClickListener.onItemClick(null, v, position, id); } } }); } addView(view); } } } } 

A solution I use is, to add all Content of the ScrollView (what should be above and under the listView) as headerView and footerView in the ListView.

So it works like, also the convertview is resued how it should be.

All these answers are wrong!!! If you are trying to put a listview in a scroll view you should re-think your design. You are trying to put a ScrollView in a ScrollView. Interfering with the list will hurt list performance. It was designed to be like this by Android.

If you really want the list to be in the same scroll as the other elements, all you have to do is add the other items into the top of the list using a simple switch statement in your adapter:

 class MyAdapter extends ArrayAdapter{ public MyAdapter(Context context, int resource, List objects) { super(context, resource, objects); } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewItem viewType = getItem(position); switch(viewType.type){ case TEXTVIEW: convertView = layouteInflater.inflate(R.layout.textView1, parent, false); break; case LISTITEM: convertView = layouteInflater.inflate(R.layout.listItem, parent, false); break; } return convertView; } } 

The list adapter can handle everything since it only renders what is visible.

Before it was not possible. But with the release of new Appcompat libraries and Design libraries, this can be achieved.

You just have to use NestedScrollView https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html

I am not aware it will work with Listview or not but works with RecyclerView.

Fragmento de código:

    

This whole problem would just go away if LinearLayout had a setAdapter method, because then when you told someone to use it instead the alternative would be trivial.

If you actually want a scrolling ListView inside another scrolling view this won’t help, but otherwise this will at least give you an idea.

You need to create a custom adapter to combine all the content you want to scroll over and set the ListView’s adapter to that.

I don’t have sample code handy, but if you want something like.

  (other content)  

Then you need to create an adapter that represents all of that content. The ListView/Adapters are smart enough to handle different types as well, but you need to write the adapter yourself.

The android UI API just isn’t as mature as pretty much everything else out there, so it doesn’t have the same niceties as other platforms. Also, when doing something on android you need to be in an android (unix) mindset where you expect that to do anything you’re probably going to have to assemble functionality of smaller parts and write a bunch of your own code to get it to work.

When we place ListView inside ScrollView two problems arise. One is ScrollView measures its children in UNSPECIFIED mode, so ListView sets its own height to accommodate only one item(I don’t know why), another is ScrollView intercepts the touch event so ListView does not scrolls.

But we can place ListView inside ScrollView with some workaround. This post , by me, explains the workaround. By this workaround we can also retain ListView ‘s recycling feature as well.

Instead of putting the listview inside Scrollview, put the rest of the content between listview and the opening of the Scrollview as a separate view and set that view as the header of the listview. So you will finally end up only list view taking charge of Scroll.

This library is the easiest and quickest solution to the problem.

Here is my version of the code that calculates total height of the list view. Esta funciona para mí:

  public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null || listAdapter.getCount() < 2) { // pre-condition return; } int totalHeight = 0; int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(BCTDApp.getDisplaySize().width, View.MeasureSpec.AT_MOST); int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); for (int i = 0; i < listAdapter.getCount(); i++) { View listItem = listAdapter.getView(i, null, listView); if (listItem instanceof ViewGroup) listItem.setLayoutParams(lp); listItem.measure(widthMeasureSpec, heightMeasureSpec); totalHeight += listItem.getMeasuredHeight(); } totalHeight += listView.getPaddingTop() + listView.getPaddingBottom(); totalHeight += (listView.getDividerHeight() * (listAdapter.getCount() - 1)); ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight; listView.setLayoutParams(params); listView.requestLayout(); }