Просмотр списка показывает несколько выбранных элементов

#android #android-listview

#Android #android-listview

Вопрос:

У меня такое чувство, что это связано с какой-то оптимизацией рендеринга или чем-то еще, но я не уверен, что.

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

Проблема возникает, когда список выходит за пределы экрана (он прокручивается), если я выбираю элемент вверху, а затем прокручиваю вниз, он также отображает другой выбранный элемент, который когда-то был вне поля зрения (я никогда не вижу 2 выбранных элемента на экране одновременно). Это также работает противоположным образом: если я выберу элемент внизу, а затем прокрутю вверх, он отобразит другой элемент как выбранный.

Также еще одно замечание: расстояние между выбранными элементами неравномерно, если я поворачиваю свое устройство в альбомную ориентацию, расстояние между выбранными элементами меньше.

Если неясно, в чем проблема, я также прикрепил фотографии.

Это с минимальным списком, в нем отображается только один выбранный элемент. введите описание изображения здесь

Здесь я выбрал элемент в верхней части. введите описание изображения здесь

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

Теперь для кода.

Фрагмент списка.

 public class ResultListFragment extends ListFragment {

BookListAdapter mBooksArray;
BookData api;
View footer;
ListView list;


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Activity parent = getActivity();    
        BookSearch app = (BookSearch) parent.getApplicationContext();

    api = app.bookAPI;

    mBooksArray = new BookListAdapter(/*some params*/);
    mBooksArray.currentActivity = parent;


}

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        list = (ListView) inflater.inflate(R.layout.search_results, null);

    footer = inflater.inflate(R.layout.load_more, null);

    return list;
}

public void onActivityCreated( Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    list.addFooterView(footer);

    list.setAdapter(mBooksArray);
}

}
 

И ArrayAdapter, цвет меняется в методе onClick.

 public class BookListAdapter extends ArrayAdapter<Book> {

ArrayList<Book> books;
private BookData bookData;
Activity currentActivity;
final BookListAdapter self = this;
private View selected = null;



public void update() {
    currentActivity.runOnUiThread(new Runnable() {
        public void run() {     
            self.notifyDataSetChanged();
        }
    }); 
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null) {

        LayoutInflater vi = (LayoutInflater) getContext().getSystemService(
                Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.search_list_view_item, null);
    }
    /*some code to set the image and text */
    v.setOnClickListener(new OnItemClickListener(position));
    return v;
}

public void onClick(int position, View view) {
            // this log always reports the correct position when i select a list item
    Log.i(new Integer(position).toString(), books.get(position).title);
    if(selected != null) {
        selected.setBackgroundResource(R.drawable.list_view_bg);
    }
    selected = view;
    selected.setBackgroundResource(R.color.listSelected);

}

private class OnItemClickListener implements OnClickListener{           
        private int mPosition;

        OnItemClickListener(int position){
            mPosition = position;
        }
        @Override
        public void onClick(View view) {
        BookListAdapter.this.onClick(mPosition, view);
        }               
    }
}
 

Ответ №1:

ListView перерабатывает представления (часть с View v = convertView; if (v == null) { } ... ), поэтому вы устанавливаете фон для представления, которое будет использоваться снова и снова. Вместо этого вам также необходимо установить флаг «selected» для вашей модели (самого Book объекта). В той части вашего getView , которая закомментирована, вы затем говорите:

 if (book.isSelected()) { 
  v.setBackgroundResource(R.color.listSelected) 
}
 

Комментарии:

1. Итак, я прав, полагая, что при прокрутке списка вниз он вызывает метод getView для создания других элементов в списке по мере их приближения к просмотру?

2. Да, getView() вызывается для каждой строки. Он сохраняет более или менее количество видимых представлений в кэше и повторно использует их после этого. Таким образом, при прокрутке вниз тот же вид, который использовался для первого элемента, будет использоваться для элемента n 1 (или около того). Вот почему вы должны каждый раз устанавливать каждое свойство, которое вам нужно, в представлении, включая фон.