73

How can I change background color of ListView items on a per-item basis. When I use android:backgroundColor in the ListView item layout I can achieve this, however the list selector is no longer visible. I can make the selector visible again by setting drawSelectorOnTop to true but then the selector overlays the whole item.

Any ideas how to change those background colors and keep the selector?

PS I would rather not change the selector itself.

EDIT: Authors of GMail application have managed to achieve exactly this so it's definitely possible.

apaderno
  • 28,547
  • 16
  • 75
  • 90
Marek Stój
  • 4,075
  • 6
  • 49
  • 50
  • I have answer this here ... https://stackoverflow.com/questions/18917214/change-background-colour-of-current-listview-item-in-adapter-getview-method/56853441#56853441 – Goddard Jul 02 '19 at 13:54

18 Answers18

37

You have to create a different state drawable for each color you want to use.

For example: list_selector_read.xml and list_selector_unread.xml.

All you need to do is set everything to transparent except the android:state_window_focused="false" item.

Then when you are drawing your list you call setBackgroundResource(R.drawable.list_selector_unread/read) for each row.

You don't set a listSelector on the ListView at all. That will maintain the default selector for your particular flavor of Android.

Hawkee
  • 2,027
  • 23
  • 20
  • 7
    +1 This should be the accepted answer. And `row.setBackgroundResource()` happens either in `YourCustomArrayAdapter.getView()` OR else you can forego this altogether by simply setting `android:background="@drawable/your_list_entry_selector"` on the outermost element of `res/layout/your_list_entry_layout.xml`. – Engineer Apr 25 '13 at 09:25
  • 1
    wouldn't mind example of the code that goes into list_selector_read.xml – Zapnologica Jun 03 '14 at 10:58
  • @Zapnologica It's a standard [Color State List resource](https://developer.android.com/guide/topics/resources/color-list-resource). You can always check the Android source repo online and look at their style resources for insight. – MandisaW Jul 17 '18 at 19:20
  • Correction: A [State List Drawable resource](https://developer.android.com/guide/topics/resources/drawable-resource#StateList) is needed here, not a Color State List. – MandisaW Jul 17 '18 at 19:34
28

This is a modification based on the above code, a simplest code:

private static int save = -1;

public void onListItemClick(ListView parent, View v, int position, long id) { 

    parent.getChildAt(position).setBackgroundColor(Color.BLUE);

    if (save != -1 && save != position){
        parent.getChildAt(save).setBackgroundColor(Color.BLACK);
    }

    save = position;                

}

I hope you find it useful

greetings!

23

Ok, I got it to work like this:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="false" android:drawable="@color/BackgroundColor" />
    <item android:drawable="@color/transparent" />
</selector>

YMMV!

Adam
  • 400
  • 3
  • 8
11

No one seemed to provide any examples of doing this solely using an adapter, so I thought I would post my code snippet for displaying ListViews where the "curSelected" item has a different background:

final ListView lv = (ListView)findViewById(R.id.lv);
lv.setAdapter(new BaseAdapter()
{
    public View getView(int position, View convertView, ViewGroup parent)
    {
        if (convertView == null)
        {
            convertView = new TextView(ListHighlightTestActivity.this);
            convertView.setPadding(10, 10, 10, 10);
            ((TextView)convertView).setTextColor(Color.WHITE);
        }

        convertView.setBackgroundColor((position == curSelected) ? 
            Color.argb(0x80, 0x20, 0xa0, 0x40) : Color.argb(0, 0, 0, 0));
        ((TextView)convertView).setText((String)getItem(position));

        return convertView;
    }

    public long getItemId(int position)
    {
        return position;
    }

    public Object getItem(int position)
    {
        return "item " + position;
    }

    public int getCount()
    {
        return 20;
    }
});

This has always been a helpful approach for me for when appearance of list items needs to change dynamically.

ubzack
  • 1,878
  • 16
  • 16
9
mAgendaListView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//view.setBackgroundColor(Color.RED);

for(int i=0; i<parent.getChildCount(); i++)
{
     if(i == position)
     {
               parent.getChildAt(i).setBackgroundColor(Color.BLUE);
     }
     else
     {
               parent.getChildAt(i).setBackgroundColor(Color.BLACK);
     }

 }
preds
  • 656
  • 6
  • 7
Mbolland
  • 285
  • 1
  • 3
  • 4
8

From the source code of Android's 2.2 Email App:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_window_focused="false" android:state_selected="true"
        android:drawable="@android:color/transparent" />
    <item android:state_selected="true"
        android:drawable="@android:color/transparent" />
    <item android:state_pressed="true" android:state_selected="false"
        android:drawable="@android:color/transparent" />
    <item android:state_selected="false"
        android:drawable="@color/message_item_read" />
</selector>

Nothing more to say...

Misha Akopov
  • 12,241
  • 27
  • 68
  • 82
ThePCWizard
  • 3,338
  • 2
  • 21
  • 32
7

the easiest way is this. Inside your ListArrayAdapter just do this

if(your condition here) rowView.setBackgroundColor(Color.parseColor("#20FFFFFF"));

don't over complicate

OWADVL
  • 10,704
  • 7
  • 55
  • 67
  • 3
    this is not answering the question asked .. he wants to maintain list selector with a different background color for some rows .. your answer will remove list selector style ! – Mohammad Zekrallah Jan 31 '16 at 10:37
  • 1
    @MohammadZekrallah I guess I'm a naughty boy that will not receive any gifts for Christmas – OWADVL Jan 31 '16 at 11:55
  • Though it doesn't answer the specific question, served a purpose in my app. Thanks. – Victor Lee Feb 21 '17 at 22:12
6

Did you mean to change the background color of the custom listitems when you click on it?

If so:

You just add the following code to your listview layout in xml.


android:drawSelectorOnTop="true" android:listSelector="@android:drawable/list_selector_background"


The list selector here uses default selector which has a dark grey color. You can make your own drawable and assign it to the list selector as above.

Hope this is what you wanted.

Kijewski
  • 25,517
  • 12
  • 101
  • 143
PrasadW
  • 397
  • 6
  • 19
5

Simple code to change all in layout of item (custom listview extends baseadapter):

lv.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {

            RelativeLayout layout=(RelativeLayout) arg1.findViewById(R.id.rel_cell_left);
            layout.setBackgroundColor(Color.YELLOW);



        }
    });
2

By changing a code of Francisco Cabezas, I got the following:

private int selectedRow = -1;

...

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    parent.getChildAt(position).setBackgroundResource(R.color.orange);
    if (selectedRow != -1 && selectedRow != position) {
        parent.getChildAt(selectedRow).setBackgroundResource(R.color.black);
    }
    selectedRow = position;
CoolMind
  • 26,736
  • 15
  • 188
  • 224
2

Following way very slowly in the running

mAgendaListView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//view.setBackgroundColor(Color.RED);

for(int i=0; i<parent.getChildCount(); i++)
{
     if(i == position)
     {
               parent.getChildAt(i).setBackgroundColor(Color.BLUE);
     }
     else
     {
               parent.getChildAt(i).setBackgroundColor(Color.BLACK);
     }

 }

Replaced by the following

int pos = 0;
int save = -1;
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
            long id) {
            //Always set the item clicked blue background
            view.setBackgroundColor(Color.BLUE);

            if (pos == 0) {
                if (save != -1) {
                    parent.getChildAt(save).setBackgroundColor(Color.BLACK);
                }
                save = position;
                pos++;
                Log.d("Pos = 0", "Running");

            } else {
                parent.getChildAt(save).setBackgroundColor(Color.BLACK);
                save = position;
                pos = 0;
                Log.d("Pos # 0", "Running");
            }
PrDoHung
  • 21
  • 1
1

In the list view you can add android:listselector=color name that you want.

this work fine in my app.

1

The best tutorial on this can be found here.

Key sections:

  1. Surely call view.setSelected(true) in onItemClick, otherwise the you can't see the selected item background
  2. Preserve the order of states in your selector otherwise you'll see unpredictable behavior in background colors (state_selected followed by state_pressed)
Mohsen Afshin
  • 13,273
  • 10
  • 65
  • 90
1

Take a look at List14 example. In getView() you can call convertView.setBackgroundDrawable() for each entry. You could have a class member counter to decide which background to call it with to get alternating backgrounds, for example.

Heikki Toivonen
  • 30,964
  • 11
  • 42
  • 44
1

You can do This.

 final List<String> fruits_list = new ArrayList<String>(Arrays.asList(fruits));

    // Create an ArrayAdapter from List
    final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>
            (this, android.R.layout.simple_list_item_1, fruits_list){
        @Override
        public View getView(int position, View convertView, ViewGroup parent){
            // Get the current item from ListView
            View view = super.getView(position,convertView,parent);
            if(position %2 == 1)
            {
                // Set a background color for ListView regular row/item
                view.setBackgroundColor(Color.parseColor("#FFB6B546"));
            }
            else
            {
                // Set the background color for alternate row/item
                view.setBackgroundColor(Color.parseColor("#FFCCCB4C"));
            }
            return view;
        }
    };

    // DataBind ListView with items from ArrayAdapter
    lv.setAdapter(arrayAdapter);
}

}

0

If the setBackgroundColor is added for onItemClick event, it will not work unless you can put it after the click event.

Try to add debug code in the adapter's getView method, you will find that getView will be called again whenever you click on the screen. So, after you set the background color, the system will redraw the screen with original setting. Don't know why it waste resource to rebuild the screen whenever it's being click, there already have other way that we can notify the system to redraw the screen when needed.

Maybe you can add some control flag to determine the background color for individual row, then modify the getView method to set the color according to this control flag. So, the background color will be changed when it redraw the screen.

I'm also looking for an official solution on it.

keyser
  • 18,829
  • 16
  • 59
  • 101
0

I tried all answers above .. none worked for me .. this is what worked eventually and is used in my application .. it will provide read/unread list items colors while maintaining listselector styles for both states :

<ListView
                android:id="@+id/list"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:listSelector="@drawable/selectable_item_background_general"
                android:drawSelectorOnTop="true"
                android:fadingEdge="none"
                android:scrollbarStyle="outsideOverlay"
                android:choiceMode="singleChoice" />

selectable_item_background_general.xml :

<selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="@android:integer/config_mediumAnimTime">
    <item android:state_pressed="false" android:state_focused="true" android:drawable="@drawable/bg_item_selected_drawable" />
    <item android:state_pressed="true" android:drawable="@drawable/bg_item_selected_drawable" />
    <item android:drawable="@android:color/transparent" />
</selector>

bg_item_selected_drawable.xml :

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#12000000" />
</shape>

notification_list_itemlayout.xml :

<RelativeLayout 
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/rowItemContainer"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">

    <RelativeLayout 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="8dp"
        android:paddingLeft="16dp"
        android:paddingStart="16dp"
        android:paddingRight="16dp"
        android:paddingEnd="16dp">

            <ImageView
                android:id="@+id/imgViewIcon"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:src="@drawable/cura_logo_symbol_small"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_marginRight="8dp"
                android:layout_marginEnd="8dp" />
            <TextView
                android:id="@+id/tvNotificationText"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignTop="@+id/imgViewIcon"
                android:layout_toRightOf="@+id/imgViewIcon"
                android:layout_toEndOf="@+id/imgViewIcon"
                android:textSize="@dimen/subtitle"
                android:textStyle="normal" />
            <TextView
                android:id="@+id/tvNotificationTime"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="1dip"
                android:layout_below="@+id/tvNotificationText"
                android:layout_toRightOf="@+id/imgViewIcon"
                android:layout_toEndOf="@+id/imgViewIcon"
                android:textSize="@dimen/subtitle" />
        </RelativeLayout>
</RelativeLayout>

Finally, in your adapter :

if (!Model.Read)
    rowItemContainer.SetBackgroundColor (Android.Graphics.Color.ParseColor ("#FFFDD0")); // unread color
else
    rowItemContainer.SetBackgroundColor (Android.Graphics.Color.White); // read color
0

That's what I used (Kotlin):

if(blablabla == "whatever") {
    view.setBackgroundColor(getColor(context, R.color.teal_200))
} else {
    view.setBackgroundColor(getColor(context, R.color.teal_700))
}
Laurent
  • 188
  • 2
  • 13