Marshall Brekka
Marshall Brekka

Reputation: 1196

List view shows multiple selected items

I have a feeling this is due to some sort of rendering optimization or something, but I'm not sure what.

I have a list view and when an item is selected, I change its background color so that it visually remains selected.

The problem occurs when the list extends beyond the screen (it scrolls), if I select an item near the top and then scroll down it also displays another selected item that was once out of the view (i can never see 2 selected items on the screen at the same time). This also works in the opposite way, if I select an item near the bottom and then scroll to the top, it will display another item as being selected.

Also another note, the distance between the selected items is not uniform, if i rotate my device into landscape, the distance between the selected items is less.

If it's not clear what the problem is I also attached pictures.

This is with a minimal list, it only displays one selected item. enter image description here

Here I have selected an item near the top. enter image description here

After scrolling down (see scroll bar) it displays another item as being selected. enter image description here

Now for the code.

The list fragment.

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);
}

}

And the ArrayAdapter, the color gets changed in the onClick method.

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);
        }               
    }
}

Upvotes: 3

Views: 2151

Answers (1)

dmon
dmon

Reputation: 30168

The ListView recycles views (the part with View v = convertView; if (v == null) { } ...), so you're setting the background on a view that will be used again and again. Instead, you also need to set a "selected" flag on your model (the Book object itself). In the part of your getView that is commented out, you then say:

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

Upvotes: 2

Related Questions