Layout_width в ListView

Итак, я столкнулся с проблемой с атрибутом layout_width listView.

В моем проекте у меня было фоновое изображение для моего списка, которое не соответствовало ширине экрана. Поэтому я установил layout_width на wrap_content, и я горизонтально перечислил listView.

Кажется, что это была плохая идея, потому что в адаптере метод GetView вызывался более чем в 3 раза по сравнению с количеством отображаемых ячеек. Если я установил layout_width на fill_parent, проблема будет решена. Я создал простой проект, который показывает проблему.

Вот xml активности:

<?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>

Элемент 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>

И, наконец, 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);
        }
}
}

Итак, мое решение состоит в том, чтобы просто установить layout_width на fill_parent и изменить изображение фона списка, чтобы добавить некоторые прозрачные границы, чтобы они соответствовали размеру экрана.

Но я хотел бы знать, почему эта проблема возникает с wrap_content в listview и почему это не в документе, если это известная проблема...

Ответ 1

Установив ширину в "wrap_content", вы указываете, что ListView будет таким же широким, как и самый широкий из его дочерних элементов. Поэтому ListView должен измерять свои элементы и получать элементы, которые он должен вызвать getView() на адаптере. Это может происходить несколько раз в зависимости от количества пропусков макета, поведения родительского макета и т.д.

Помните, что нет никаких гарантий относительно того, сколько раз getView() вызывается в адаптере, и в каких заказах вызовы будут выполняться. Поэтому вы должны реализовать getView() как можно более эффективно. Суть в том, что это не проблема, это ожидаемое поведение в этой ситуации.

Ответ 2

Ответ прост: если вы установите ширину макета или высоту макета вашего ListView на wrap_content, ListView попытается измерить каждый единственный вид, который прикреплен к нему, - это определенно не то, что вы хотите.

Вообще говоря, избегайте установки wrap_content для ListViews или GridViews в любое время.