16

Is there a way to have a ListView with the with equal to the longest row? Setting wrap_content for the ListView 's width has no effect. The ListView covers the whole screen horizontally.

This is the activity layout

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ListView   android:id="@+id/listview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/country_picker_bg" />

and this is the row xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<LinearLayout 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:layout_marginBottom="@dimen/padding"
    android:padding="@dimen/padding"
    android:background="@drawable/white_round_rect" >
    <TextView android:id="@+id/title"
        style="@style/GreyTextView"
        android:layout_marginLeft="@dimen/padding"/>    
    <ImageView  
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:src="@drawable/orange_arrow_selector"/>
</LinearLayout>

Thank you, Gratzi

Hussain
  • 5,552
  • 4
  • 40
  • 50
Gratzi
  • 4,633
  • 12
  • 42
  • 58
  • Can you please be more specific? I've tried to create a custom listview and to set the width in the onMeasure method, but nothing happened. – Gratzi Jul 01 '11 at 11:23
  • post your xml as well as add further details in your question. – Balaji Khadake Jul 01 '11 at 11:40
  • check your all drawable background size(for ListView and TextView).Do you getting any exception? I think you have to add android:layout_width proprty to TextView. what is value of @dimen/padding in android:layout_marginLeft="@dimen/padding? – Balaji Khadake Jul 01 '11 at 12:08
  • The text view's width is set in the style. I has nothing to do with the rows. The rows are not full screen width, only the listview is. – Gratzi Jul 01 '11 at 12:20

2 Answers2

38

Sometimes, you know there will always be a limited number of items, maybe 5, maybe 40. In those times you still want to use a ListView and you still want to wrap content.

For those times there is this method:

/**
 * Computes the widest view in an adapter, best used when you need to wrap_content on a ListView, please be careful
 * and don't use it on an adapter that is extremely numerous in items or it will take a long time.
 *
 * @param context Some context
 * @param adapter The adapter to process
 * @return The pixel width of the widest View
 */
public static int getWidestView(Context context, Adapter adapter) {
    int maxWidth = 0;
    View view = null;
    FrameLayout fakeParent = new FrameLayout(context);
    for (int i=0, count=adapter.getCount(); i<count; i++) {
        view = adapter.getView(i, view, fakeParent);
        view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
        int width = view.getMeasuredWidth();
        if (width > maxWidth) {
            maxWidth = width;
        }
    }
    return maxWidth;
}

Use it like so (notice I added some extra space to the width just in case):

listView.getLayoutParams().width = getWidestView(mContext, adapter)*1.05;
satur9nine
  • 13,927
  • 5
  • 80
  • 123
  • 2
    This solution worked perfectly in a fragment-based app that I have. On a ListView with 15 items, System.currentTimeMillis() showed that the ListView could be resized to the optimal width in 6 milliseconds. – Yojimbo Apr 16 '13 at 18:13
  • 2
    Android should do this and give it as an option to the developers. Actually I assumed the option was "wrap_content", but actually it's not. – Felix Oct 18 '16 at 09:24
  • Strike! Great answer. Thanks a lot. – Itapox Apr 24 '19 at 02:03
  • for what `*1.05` is? – ATP Apr 16 '21 at 12:57
  • @ATP The `1.05` is not required, I added it for good luck (absolutely no real reason). – satur9nine Apr 16 '21 at 15:59
15

Is there a way to have a ListView with the with equal to the longest row?

No, in part because we have no way to know what the longest row is.

Let's say that you attach a ListAdapter to the ListView, where getCount() on the ListAdapter returns a value of 1,234,567. To determine the width of the longest row, we would have to create each row and examine its width. This would take hours, and the user will not be happy during those hours.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thanks for the reply. That makes sense. I have one more question related to this: is it a good practice to create a custom listview with the width equal to the background's drawable width? If it is, how can I do that? Setting the width in onMeasure() had no effect. – Gratzi Jul 01 '11 at 13:47
  • @Gratzi: "is it a good practice to create a custom listview with the width equal to the background's drawable width?" -- usually, you make the background drawable resizeable (e.g., nine-patch PNG or `ShapeDrawable`), and design the `ListView` size around the actual data being presented in the list. The data is what the user will care about, much more than your background. – CommonsWare Jul 01 '11 at 13:50
  • @Gratzi: Making a `ListView` size be dependent on the size of a background image is not a good practice in general. – CommonsWare Jul 01 '11 at 14:26