Layout_width of a ListView
Asked Answered
S

2

5

Ok so I encountered an issue with the attribut layout_width of a listView.

In my project I had a background image for my listview that didn't fit the width of the screen. So I set the layout_width on wrap_content, and I centered horizontally the listView.

It seems that this was a bad idea, because in the adapter the GetView method was called more than 3 times the number of cell displayed. If I set the layout_width on fill_parent the problem is resolved. I created a simple project that shows the problem.

Here is the xml of the activity :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView
    android:id="@android:id/list"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
/>
</RelativeLayout>

The item_list xml :

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="10dp"
    android:textSize="16sp" >
</TextView>

And finally the Activity :

package fr.example.android.listviewbug;

import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;

public class ExampleListViewBugActivity extends ListActivity{
    public static int cpt;

    public static final String[] COUNTRIES = new String[] {
        "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
        "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
        "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
        "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
        "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
        "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
        "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
        "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
        "Cayman Islands", "Central African Republic", "Chad", "Chile"};

    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);

      cpt = 0;
      setListAdapter(new CustomArrayAdapter(this, R.layout.list_item, COUNTRIES));  
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("AdapterTest", "onDestroy()");
    }

    private class CustomArrayAdapter extends ArrayAdapter<String>{
        public CustomArrayAdapter(Context context, int textViewResourceId, String[] countries) {
            super(context, textViewResourceId, countries);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            Log.d("AdapterTest", " cpt:"+ ++cpt);
            return super.getView(position, convertView, parent);
        }
}
}

So my solution is to simply set the layout_width on fill_parent, and modify the image of the listview background to add some transparent borders to fit the screen size.

But I'd like to know why this issue appears with wrap_content on a listview, and why it's not in the doc if it's a known problem...

Shattuck answered 24/11, 2010 at 18:32 Comment(0)
T
20

By setting the width to "wrap_content" you are telling ListView to be as wide as the widest of its children. ListView must therefore measure its items and to get the items it has to call getView() on the Adapter. This may happen several times depending on the number of layout passes, the behavior of the parent layout, etc.

Remember there are no guarantees on the number of times getView() is invoked on the Adapter, nor in what orders the calls will happen. You must therefore implement getView() to be as efficient as possible. The bottom line is, this is not an issue, it's the expected behavior in this situation.

Tayler answered 24/11, 2010 at 22:1 Comment(2)
You are the father of listview romain.Finespun
This is important, I think LINT should warn about thisFlavory
A
11

The answer is simple: If you set the layout width or layout height of your ListView to wrap_content the ListView will try to measure every single view that is attached to it - which is definitely not what you want.

Generally speaking, avoid setting wrap_content for ListViews or GridViews at all times.

Alpinist answered 24/11, 2010 at 18:58 Comment(1)
If a ListView contains only 2 items, that would be very good to measure their widths, but the ListView doesn't. So, a problem is not in a wrap_content but in the ListView.Cookson

© 2022 - 2024 — McMap. All rights reserved.