Why do ListView items not grow to wrap their content?

AndroidListview

Android Problem Overview


I have a rather complex ListView, with variable list item heights. Under certain conditions, I need to display an additional view in a list item, which is hidden by default (View.GONE). By enabling it (View.VISIBLE), the list item grows in height (or at least it's supposed to).

The problem: Even though I declare the item's root layout to wrap_content, and each component in the item to fill_parent, the view I hide/show which is supposed to change the item's height is simply cut off at the bottom instead of its parent (the item layout) growing in height to fully display it.

Are there any gotchas related to ListViews and item layouts and item height which I may have missed?

Some more observations:

For testing purposes, I have now reduced the list item layout to just contain the root LinearLayout and an ImageView. When I set the LinearLayout height to e.g. 200dip and the ImageView to fill_parent, I would have expected the ImageView to grow until it hits the 200dip limit set by its parent.

However, the image will instead be only ever as tall as its bitmap resource (as if I had set it to wrap_content) and the whole list item will be of the same height (i.e. as if I had set it to wrap_content, too).

If however, I set the image height to e.g. 200dip, then the list item will grow in height, and so will the item layout.

In other words, the layout_height of the list item layout is completely ignored, and so is any height value on ImageView other than a hard-coded pixel value.

Android Solutions


Solution 1 - Android

I managed to fix this, but I don't understand why.

As I mentioned, I had set the layout_height of the list item layout to wrap_content (since fill_parent is meaningless here, considering that a ListView is indefinitely tall).

However, I had set the layout_height of all views inside that layout to fill_parent. The problem disappeared when setting them to wrap_content instead.

This raises two other questions:

  1. What are the semantics of a view asking to fill_parent, when the parent wraps_content? Which size request takes precedence?

  2. How would I ever make a view fill a list item if fill_parent apparently doesn't work?

Thanks for your input guys.

Solution 2 - Android

Try this: http://www.java2s.com/Code/Android/UI/setListViewHeightBasedOnChildren.htm

public class Utils {

    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);
        listView.requestLayout();
    }     
}

Solution 3 - Android

How are you inflating your rows?

If you are not using it right now, try using LayoutInflater#inflate(layoutId, parent, false) (where parent is the AdapterView supplied to getView() or newView()):

v = getLayoutInflater().inflate(R.layout.list_item, parent, false);

Solution 4 - Android

The problems with layout could be caused by ScrollView to be the wrapper

I stumbled upon some note in http://developer.android.com/reference/android/widget/ExpandableListView.html

"...Note: You cannot use the value wrap_content for the android:layout_height attribute of a ExpandableListView in XML if the parent's size is also not strictly specified (for example, if the parent were ScrollView you could not specify wrap_content since it also can be any length. However, you can use wrap_content if the ExpandableListView parent has a specific size, such as 100 pixels."

I removed wrapping ScrollView and linear layout started working properly. Now its only to understand how to wrap the stuff to ScrollView. God help me

But anyway this is really weird behavior. I think that fill_parent is not really correct wording. When using heirarchyviewer tool I always see WRAP_CONTENT and MATCH_PARENT values for layout_width and leayout_height. So probably fill_parent is actually means match_parent which puts me in cognitive dissonance.

Solution 5 - Android

I use the "AbsListView.LayoutParams" to configure the width and height manually inside "Adapter.getView()".

Solution 6 - Android

If you're using a custom View in as the list item that is resizing, then you can take from PeBek's answer and do this when you construct the View

addOnLayoutChangeListener(
            new OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View _, int __, int ___, int ____, int bottom, int _____, int ______,
                                           int _______, int old_bottom) {
                    final ListView list_view = (ListView) getParent();
                    final ViewGroup.LayoutParams params = list_view.getLayoutParams();
                    params.height += bottom - old_bottom;
                    list_view.setLayoutParams(params);
                    list_view.requestLayout();
                }
            });

When the View gets resized this callback method will me run and it updates the ListView height to include the change in height (delta bottom). The other values, if they prove useful for you are view (reference to the view), left, top, right, bottom, old_left, old_top, old_right, old_bottom. It works for expanding and collapsing the view.

API 11 is required for OnLayoutChangeListener, don't know if there's a backward compatible way to do so.

Solution 7 - Android

I had the same problem: i would like to have a list inside my activity that fill all the screen either when the device is in vertical than in horizontal orientation. I solve the problem using al Linear Layout that have height that have to fill_parent, and setting the height of the item in the list to 0dp while the layout_weight is setter to 1.

android:layout_weight="1"
android:layout_height="0dp"

Solution 8 - Android

this works for me

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:padding="@dimen/activity_vertical_margin">

    <TextView
        android:id="@+id/tv_status"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="17sp"
        android:text="@string/text_list_devices" />

    <ListView
        android:id="@+id/lv_paired"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:cacheColorHint="#00000000"
        android:layout_above="@+id/signup_t"
        android:layout_below="@id/tv_status"
        />

    <Button

        android:id="@+id/signup_t"
        style="?android:textAppearanceSmall"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:textColor="@android:color/white"
        android:layout_alignParentBottom="true"
        android:text="Print All Records"
        android:typeface="sans"
        android:layout_marginLeft="45dp"
        android:layout_marginRight="45dp"
        android:textSize="24sp"
        android:background="@drawable/selector_for_button"
        android:textStyle="bold" />
</RelativeLayout>

Solution 9 - Android

Things to note about column alignment:

  • The container LinearLayout element uses horizontal orientation and android:layout_width as match_parent.

  • The TextView elements use android:layout_width="0dp"

  • Each of the two TextView elements uses android:layout_weight="1" so that they use equal amounts of the available width.

  • The android:layout_width property of each TextView element is set to "0dp".

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatthiasView Question on Stackoverflow
Solution 1 - AndroidMatthiasView Answer on Stackoverflow
Solution 2 - AndroidPeBekView Answer on Stackoverflow
Solution 3 - AndroidCommonsWareView Answer on Stackoverflow
Solution 4 - AndroidkirhgoffView Answer on Stackoverflow
Solution 5 - AndroidroysView Answer on Stackoverflow
Solution 6 - AndroidDandre AllisonView Answer on Stackoverflow
Solution 7 - AndroidFraView Answer on Stackoverflow
Solution 8 - AndroidNouman ChView Answer on Stackoverflow
Solution 9 - AndroidBudhdi SharmaView Answer on Stackoverflow