Java – Different selection colors for different ListView items

Different selection colors for different ListView items… here is a solution to the problem.

Different selection colors for different ListView items

I have the following requirements:

  • Different colors for different ListView items
  • Colors are specified dynamically in the code
  • The color should be displayed only when the ListView item is pressed/selected
  • The color of the ListView item should not change permanently

For whatever reason, it doesn’t seem as simple as I thought. The only solution that goes at least a little in the right direction is this: https://stackoverflow.com/a/16978159/658718

Note that this does not change the selection color, but it does change the background color permanently, and if you scroll down a bit, it already changes the background color of the ListView item.

How do I fix this?

Solution

The difficulty here is that the pressed/selected colors are dynamic. You cannot use a static XML color status list. But you can create ColorStateList via code. Here’s how to do it.

You only need to implement ListAdapter:

private class MyListAdapter implements ListAdapter{

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView!=null){
             CheckedTextView textView = (CheckedTextView)convertView;
             textView.setText("the text for item "+position);
             textView.setTextColor(makeColorStateListForItem(position));
             return textView;
        }else{
             CheckedTextView textView = new CheckedTextView(parent.getContext());
             textView.setText("the text for item "+position);
             textView.setTextColor(makeColorStateListForItem(position));
             return textView;
        }
    }

private ColorStateList makeColorStateListForItem(int position){
        int pressedColor = pressedColorForItem(position);
        int checkedColor = checkedColorForItem(position);
        int defaultColor = defaultColorForItem(position);
        ColorStateList colorStateList = new ColorStateList(
                new int[][]{
                        new int[]{android. R.attr.state_pressed},
                        new int[]{android. R.attr.state_checked},
                        new int[]{0},
                },
                new int[]{
                        pressedColor, //use when state is pressed
                        checkedColor, //use when state is checked, but not pressed
                        defaultColor}); used when state is not pressed, nor checked 
    }

private int pressedColorForItem(int position){
        write your business logic to determine color here
        return ...;
    }

private int checkedColorForItem(int position){
        write your business logic to determine color here
        return ...;
    }

private int defaultColorForItem(int position){
        return Color.WHITE;
    }

all other adapter methods
    //...

Please note that using Android. R.attr.state_checked instead of more intuitive Android. R.attr.state_selected because state_selected is not very precisely defined with a touch screen (i.e. state_selected can give the expected behavior on the emulator, but on a real device it may fail).

On the other hand, state_checked + CheckedTextView will work fine on emulators and real devices.

Just call List.setChoiceMode(...); In initializing the listView and ListView.setItemChecked in clickListener.

final ListView listView = ...
listView.setAdapter(new MyListAdapter());
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        listView.setItemChecked(position,true);
    }
});

Edit: Change project background: Simply create a StateListDrawable instead of a simple ColorStateList:

private Drawable makeBackgroungForItem(int position){
    int pressedColor = pressedBackgroundColorForItem(position);
    int checkedColor = checkedBackgroundColorForItem(position);
    int defaultColor = defaultBackgroundColorForItem(position);
    StateListDrawable stateListDrawable = new StateListDrawable();
    stateListDrawable.addState(new int[]{android. R.attr.state_list_pressed}, new ColorDrawable(pressedColor));
    stateListDrawable.addState(new int[]{android. R.attr.state_list_checked}, new ColorDrawable(checkedColor));
    stateListDrawable.addState(new int[]{0, new ColorDrawable(defaultColor));
    return stateListDrawable;
}

And in getView(...).

textView.setBackground(makeBackgroungForItem(position));

Related Problems and Solutions