Android-диалог со списком, использующий пользовательский адаптер списка, который случайным образом теряет информацию при прокрутке - PullRequest
3 голосов
/ 01 марта 2012

Я создаю диалоговое окно и заполняю его списком, в котором используется настраиваемый адаптер списка. Это работает нормально, но я заметил, что когда список достаточно длинный для прокрутки, выполнение этого назад и вперед приведет к тому, что некоторые из моих элементов списка случайно потеряют часть своих данных. Я заметил, что это всегда одни и те же элементы списка. Например, каждый элемент списка будет иметь заголовок, изображение и дату. Даты, кажется, исчезают на некоторых, когда я прокручиваю. Они всегда рядом, когда я начинаю диалог, и они всегда исчезают, когда я прокручиваю.

Странная вещь в том, что моя строка списка состоит из нескольких TextViews в 2 строки, и только нижняя строка TextViews исчезает ... Есть идеи?

Код для моего диалога

 itemSendPickerDialog = new Dialog(this);
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
   builder.setTitle("Select Item to Send");
    ListView lv = new ListView(this);
    Cursor c = mDbHelper.fetchItemsByDate(id);
    c.moveToFirst();

    int i = R.layout.send_item_menu_row;
    MyListAdapter ia = new MyListAdapter(this, mainListBackground, c, true);
    lv.setAdapter(ia);

    builder.setView(lv);
    itemSendPickerDialog = builder.create();
    itemSendPickerDialog.show();

И мой класс адаптера списка:

class MyListAdapter extends ResourceCursorAdapter {
    public MyListAdapter(Context context, int i, Cursor cursor, boolean...sending) {
        super(context, i, cursor);
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {

        TextView title = (TextView) view.findViewById(R.id.item_name);

        title.setText(cursor.getString(cursor.getColumnIndex(TripsDbAdapter.KEY_ITEM_TITLE)));

        Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        int width = display.getWidth();
        width = width - 150;
        ViewGroup.LayoutParams params = title.getLayoutParams();
        params.width = width;
        title.setLayoutParams(params);

        String cat = cursor.getString(cursor.getColumnIndex(TripsDbAdapter.KEY_ITEM_CATEGORY));
        if (cat.equalsIgnoreCase("trip notes")) {
            LinearLayout ll = (LinearLayout) view.findViewById(R.id.item_datetime_holder);
            ll.setVisibility(View.INVISIBLE);
        }
        TextView date = (TextView) view.findViewById(R.id.item_date);
        date.setText(cursor.getString(cursor.getColumnIndex(TripsDbAdapter.KEY_DEP_DATE)));

        TextView time = (TextView) view.findViewById(R.id.item_time);
        time.setText(cursor.getString(cursor.getColumnIndex(TripsDbAdapter.KEY_DEP_TIME)));

        ImageView iv = (ImageView) view.findViewById(R.id.image_icon);
        if (iv != null) {
            int index = cursor.getColumnIndex(TripsDbAdapter.KEY_ITEM_TYPE);

            String type = cursor.getString(index);
            if (type != null) {

            } else {
                type = "notes";
            }

            iv.setImageResource(getTypeResource(type));
        }

    }
}

Ответы [ 4 ]

1 голос
/ 12 марта 2012

Я тоже сталкивался с этой проблемой ... Проблема, с которой вы сталкиваетесь, связана с перезапуском представлений LIstView при прокрутке вверх / вниз.В вашем случае ListView предоставляет вам те переработанные представления, свойства которых вы изменили, сделав их невидимыми.Некоторые возможные решения могут быть:

1) Когда cat.equalsIgnoreCase («заметки о поездке») становится правдой, некоторые представления становятся невидимыми.Этот невидимый вид затем перерабатывается и возвращается.Восстановленное представление по-прежнему невидимо (когда оно возвращается вам), поэтому вы можете сделать это невидимое представление видимым в начале вашего ListAdapter каждый раз.Вы можете поместить этот код в начало метода bindView, где сначала нужно сделать видимым макет, а затем продолжить работу с остальной логикой. (Короче говоря, даты на вашем дисплее не исчезают, а просто не видны).

2) Переопределите getViewTypeCount() в вашем адаптере.Из вашего codenippet похоже, что у вас есть два типа строк (один, в котором R.id.item_datetime_holder невидим, а другой - в видимом), поэтому верните 2 из этого метода (пожалуйста, сделайте несколько проб и ошибок).Это должно решить проблему.

public int getViewTypeCount() {

        return 2;
    }

Вы найдете отличное объяснение по этой ссылке http://logc.at/2011/10/10/handling-listviews-with-multiple-row-types/

3) Вы можете раздуть совершенно разные макеты в зависимости от состояния if.Но эффективность будет немного меньше.

0 голосов
/ 05 марта 2012

Я понял, что код, который делает это, находится в моем классе адаптера списка

String cat = cursor.getString(cursor.getColumnIndex(TripsDbAdapter.KEY_ITEM_CATEGORY));
        if (cat.equalsIgnoreCase("trip notes")) {   
            LinearLayout ll = (LinearLayout) view.findViewById(R.id.item_datetime_holder);
            ll.setVisibility(View.INVISIBLE);
        }

Я скрываю некоторые элементы макета в зависимости от категории, и по какой-то причине при добавлении представления списка в конструктор AlertDialog, похоже, происходит смешивание элементов. Я не знаю точно, как я собираюсь это исправить, но сейчас, если я просто удалю функцию невидимости, мои данные не исчезнут.

0 голосов
/ 10 марта 2012

Я бы использовал два разных макета, в зависимости от «типа» элемента списка. Похоже, вы переключаете «тип» на основе строки cat, содержащей «заметки о поездке». Если он содержит его, то у вас будет такой же макет, как у вас сейчас, но без представления item_datetime_holder. Если он не содержит его, вы бы использовали тот же макет, что и сейчас (send_item_menu_row).

Вот хорошее руководство по использованию нескольких макетов в ListView: http://android.amberfog.com/?p=296

Кстати, я думаю, что причина того, что некоторые из ваших строк не отображаются правильно, связана с повторным использованием представления ListView. Использование нескольких макетов, как я упоминал выше, должно решить эту проблему, поскольку вы не будете изменять видимость представлений, а просто будете использовать два разных представления для рендеринга в зависимости от того, какой тип элемента списка вы отображаете.

0 голосов
/ 05 марта 2012

У меня была похожая проблема, при прокрутке списка, только элементы после высоты окна решили получить свои данные, повторяющиеся из индекса 0 - так что если последний видимый элемент был 8, следующий снова будет 0.

Так что вы можете попытаться проверить правильность индекса представления, может быть, этот метод ListView поможет

lv.getPositionForView(view);
...