Search code examples
androidlistviewlayoutcolorsandroid-cursoradapter

Can't figure out why background color has an erratic behavior when scrolling ListView


I believe this question is worth reading, in my opinion... I've tried to explain in details, yet abstracted to ease your reading.

  1. I have a ListView populated by a custom CursorAdapter.

  2. In the bindView() method, I try to set the color of the child.

  3. This child is a LinearLayout, the root layout used for items in the list. It's in the XML file R.layout.list_item, inflated in the newView() method of the custom CursorAdapter.

  4. I set the background color using the code below.

    LinearLayout root = (LinearLayout) view.findViewById(R.id.list_item_root);
    // ...
    if (isEvenDay(cal)) {
        tvDate.setText(tvDate.getText() + " *");
        root.setBackgroundColor(Color.DKGRAY);
    }
    

Don't worry about anything other than setBackgroundColor in the if block. You'll see.

Expected behavior: some children will be painted DKGRAY and will have * appended to a certain textView. Others will be the default color and not have this *. I use this * tag just to make sure it's not (directly) my code.

Behavior: when the ListView is initially displayed, it appears to be fine, as expected. When I scroll the list, it gets "weird" (I don't understand) and some children will start changing colors until all children are painted DKGRAY.

Now, the worst is that this works:

    LinearLayout root = (LinearLayout) view.findViewById(R.id.list_item_root);
    // ...
    if (isEvenDay(cal)) {
        tvDate.setText(tvDate.getText() + " *");
        root.setBackgroundColor(Color.DKGRAY);
    } else {
        root.setBackgroundColor(Color.GRAY);
    }

The proper children get painted DKGRAY and GRAY, and scrolling the List won't make the list colors go bonkers. Colors don't change and all seems OK. Except, of course, I don't want DKGRAY and GRAY, I want DKGRAY and leave the other children alone. ¬¬

Please help me!


Images below. See how * in the first column works fine between different dates, but the color does not.

1- I start scrolling and some children are already defective:

enter image description here

2- I finish scrolling up and down and finally all children are defective:

enter image description here

3- But when I set the colors for all children, scrolling won't screw it:

enter image description here


Solution

  • In order to not create a huge number of in-memory views and cause a lot of allocation and garbage collection, bindView will give you a 'recycled' view that has already been used when scrolling a large list. This view will have whatever attributes it happened to have the last time is was used. Because of this you need to explicitly set all of these attributes.

    So, if sometimes you want it gray and sometimes you want it white, you need to always set it to one or the other. There is no 'default' that you can rely on.