ListView в ArrayAdapter порядок смешаться при прокрутке

У меня есть ListView в пользовательском ArrayAdapter, который отображает значок ImageView и TextView в каждой строке. Когда я делаю список достаточно длинным, чтобы вы могли прокручивать его, порядок начинается правильно, но когда я начинаю прокручивать вниз, некоторые из ранних записей начинают снова появляться. Если я прокручу резервную копию, старый порядок изменится. Выполнение этого неоднократно в конечном итоге приводит к тому, что весь порядок списка будет казаться случайным. Таким образом, прокрутка списка либо приводит к изменению дочернего порядка, либо рисунок не освежает правильно.

Что может привести к чему-то подобному? Мне нужно, чтобы элементы отображались пользователю таким же образом, который они добавили в ArrayList, или на LEAST, чтобы оставаться в одном статическом порядке. Если мне нужно предоставить более подробную информацию, пожалуйста, дайте мне знать. Любая помощь приветствуется. Спасибо.

Ответ 1

У меня были аналогичные проблемы, но при нажатии элемента в пользовательском списке элементы на экране менялись бы последовательно. Если бы я снова щелкнул, они вернутся туда, где они были изначально.

Прочитав это, я проверил свой код, где я перегружаю метод getView. Я получал представление из convertView, и если это было null, это когда я собирал свои вещи. Однако после размещения точки останова я обнаружил, что он вызывал этот метод при каждом щелчке и последующих кликах, преобразованный образ был не пустым, поэтому элементы не были установлены.

Вот пример того, что это было:


public View getView(int position, View convertView, ViewGroup parent)
{
    View view = convertView;
    if (view == null)
    {
        LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = vi.inflate(R.layout.listitemrow, null);

        RssItem rssItem = (RssItem) super.getItem(position);
        if (rssItem != null)
        {
            TextView title = (TextView) view.findViewById(R.id.rowtitle);
            if (title != null)
            {
                title.setText(rssItem.getTitle());
            }
        }
    }
    return view;
}

Тонкое изменение перемещает ближайшую скобку для нулевой проверки на вид сразу после раздувания:


public View getView(int position, View convertView, ViewGroup parent)
{
    View view = convertView;
    if (view == null)
    {
        LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = vi.inflate(R.layout.listitemrow, null);
    }
    RssItem rssItem = (RssItem) super.getItem(position);
    if (rssItem != null)
    {
        TextView title = (TextView) view.findViewById(R.id.rowtitle);
        if (title != null)
        {
            title.setText(rssItem.getTitle());
        }
    }
    return view;
}

Я надеюсь, что это поможет другим, которые испытывают эту же проблему.

Ответ 2

Чтобы подробнее пояснить ответ фаркатов ниже более общим образом, вот мое объяснение:

Операция vi.inflate(необходимая для разбора макета строки из XML и создания соответствующего объекта View) завершается оператором if (view == null) для эффективности, поэтому инфляция одного и того же объекта не будет происходить снова и снова каждый раз, когда он появляется.

ОДНАКО, другие части метода getView используются для установки других параметров и поэтому НЕ должны быть включены в оператор if (view == null).

Аналогично, в другой распространенной реализации этого метода некоторые элементы textView, ImageView или ImageButton должны заполняться значениями из списка [позиция], используя findViewById и после этого .setText или .setImageBitmap. Эти операции должны выполняться после того, как вы создаете представление с нуля путем инфляции и получаете существующее представление, если оно не является нулевым.

Еще один хороший пример, когда это решение применяется для BaseAdapter, появляется в BaseAdapter, что приводит к тому, что ListView не работает при прокрутке

Ответ 3

ListView повторно использует объекты просмотра при прокрутке. Вы переопределяете метод getView? Вам нужно убедиться, что вы устанавливаете каждое свойство для каждого вида, не предполагайте, что он будет помнить то, что было раньше. Если вы опубликуете этот метод, кто-то, вероятно, может указать вам неверную часть.

Ответ 4

У меня есть ListView, AdapterView и View (search_options), который содержит EditText и 3 Spinners. Элементы ListView представляют собой несколько копий макета (search_options), где пользователь может добавлять дополнительные параметры в ListView, затем нажмите "Поиск" для отправки SQL-запроса, построенного в соответствии с параметрами пользователей.

Я обнаружил, что конверсия convertView indecies, поэтому я добавил глобальный список (myViews) в действие и передал его в ArrayAdapter. Затем в ArrayAdapter (getView) я добавляю каждый новый добавленный вид (myViews).

Также на getView вместо проверки, является ли convertView равным null, я проверяю, есть ли в глобальном списке (myViews) вид на выбранную (позицию). Он полностью решил проблемы, потеряв 3 дня, читающих интернет!

1- on Activity добавьте это:

Map<Integer, View> myViews = new HashMap<>();

а затем передать его в ArrayAdapter с помощью конструктора адаптера.

mSOAdapter = new SearchOptionsAdapter(getActivity(), resultStrs, myViews);

2- на getView:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    View view;
    ViewHolder viewHolder;

    if (!myViews.containsKey(position)) {
        viewHolder = new ViewHolder();
        LayoutInflater inflater = LayoutInflater.from(getContext());
        view = inflater.inflate(R.layout.search_options, parent, false);

        /// ...... YOUR CODE

        myViews.put(position, view);

        FontUtils.setCustomFontsIn(view, getContext().getAssets());

    }else {
        view = myViews.get(position);
    }

    return view;
}

Наконец, больше нет элементов смешивания...