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