Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different select colors for different list view items

I have the following requirements:

  • different colors for different list view items
  • colors are specified dynamically in the code
  • color should only be shown if the list view item is pressed/selected
  • color of the list view item should not change permanently

For whatever reasons it seems not to be as straight forward as I thought. The only solution that goes at least a little bit in the right direction is this one: https://stackoverflow.com/a/16978159/658718

The caveat is, that this does not change the on select color, but changes the background color permanently, plus it already changes the background color for list view items if you scroll down a bit.

How can I approach this?

like image 239
Mahoni Avatar asked Mar 07 '26 14:03

Mahoni


1 Answers

The difficulty here is that pressed/checked color is dynamic. You cannot use static xml color-state-list. But you can create ColorStateList by code. Here is how to do that.

You just have to implement the 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
    //...

Note the use of android.R.attr.state_checked instead of the more intuitive android.R.attr.state_selected because the state_selected is not very precisely define with a touch screen (i.e. state_selected can give the expected behavior on the emulator, but on a real device it will probably fail)

On the other hand state_checked + CheckedTextView is going to work correctly on both simulator and real device.

Just call List.setChoiceMode(...); when initializing listView and ListView.setItemChecked in the 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 : to change the item background : just 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 the getView(...)

textView.setBackground(makeBackgroungForItem(position));
like image 91
ben75 Avatar answered Mar 09 '26 05:03

ben75



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!