1

I'm trying to get a ListView to toggle the background color of its elements when they are selected (this is for selecting songs to add to a playlist). I've been mostly successful, but for some reason whenever the ListView is longer than the screen, selecting either the first or last item also toggles the background of the other. I keep track of whether an item is selected or not in an array of booleans called selectedStatus, and there's not a problem there, so it's purely a UI problem.

Here's the relevant section of the code:

boolean selectedStatus{} = new boolean[songsList.size()];

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

    lv = getListView();

    // listening for song selection 
    lv.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {
            int viewPosition = position - lv.getFirstVisiblePosition();
            if(selectedStatus[position]){
                selectedStatus[position] = false;
                View currentEntry = lv.getChildAt(viewPosition);
                currentEntry.setBackgroundResource(R.color.footercolor);
            }
            else{
                selectedStatus[position] = true;
                View currentEntry = lv.getChildAt(viewPosition);
                currentEntry.setBackgroundResource(R.color.selected);
            }
        }
    });
}

There must be some implementation detail about ListViews that I'm missing, but I can't figure out why this would be happening.

EDIT: I've realized with more testing that it actually links all list elements with positions which are equal mod 12, I just wasn't looking at a long enough list. This seems much less weird, it's just reusing elements, and I'll have to look into this ViewHolder idea.

Since a few people asked, this is all the code I have for making an adapter and populating the list:

// Adding items to ListView
ListAdapter adapter = new ArrayAdapter<String>(getActivity(),
        R.layout.playlist_builder_item, songnamesList);
setListAdapter(adapter);
  • How are you setting your listview items? I need to know what you are using for your adapter? Do you have your own extending baseAdapter or? – Unknownweirdo Mar 07 '14 at 16:59

1 Answers1

0

Sounds like you might need to create a proper ListAdapter and implement a ViewHolder.

The ViewHolder avoids the layout reuse that Android ListView implements, so as you can do slightly more complicated things by relying on the Views being the same as before.

You should hold onto the View that you're changing in a static class. For example:

static class ViewHolder {
    ImageView backgroundItem;
}

Then in your Adapter's getView method you want to get hold of that ViewHolder and if we are creating a new view, we set it to be new, otherwise we reuse the old view that we have set as a tag to the original.

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

  ViewHolder viewHolder;

  if(convertView == null){
      // Inflate the view as we normally would
      // Create a new ViewHolder
      // Set our ImageView to be equal to viewHolder's backgroundItem  
      // final step
      convertView.setTag(viewHolder);
  }else{
      // use the original ViewHolder that was already saved as a tag
      viewHolder = (ViewHolder) convertView.getTag();
  }

   // Set the background as per your own code

   // Return the convertView
   return convertView;
}

Don't forget to set your Adapter to your listview by calling the ListView setAdapter(ListAdapter adapter) method

A decent tutorial which incorporates creating an Adapter and a ViewHolder can be found here.

Further reading:

biddulph.r
  • 5,226
  • 3
  • 32
  • 47
  • Thank you for a very good explanation of what I was doing wrong. This together with R Quijano's linked post in the below comment got things working. – riemannrocker Mar 08 '14 at 02:54