How to highlight row in ListView in Android?
Asked Answered
D

8

38

I need to highlight a row in a ListView that was selected (to show the user what he chose), so, it's not the one that is going to be chosen, it's the one he chose before.

I already have the location by:

ListView.setSelection(position);

And now what I want is to select this specific row and to highlight it.

The code of the onCreate() in the activity that contains the ListView:

public class CountryView extends Activity
{
    protected static final String LOG_TAG = null;
    /** Called when the activity is first created. */
    String[] lv_arr = {};

    ListAdapter adapter;
    TextView t;
    private ListView lvUsers;
    private ArrayList<Coun> mListUsers;
    String responce=null;
    public int d;
    int selectedListItem = -1;


    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.country);

        Intent data =getIntent();

        mListUsers = getCoun();
        lvUsers = (ListView) findViewById(R.id.counlistView);


        lvUsers.setAdapter(new ListAdapter(this, R.id.counlistView, mListUsers)); 


        selectedListItem=data.getExtras().getInt("PositionInList");

       lvUsers.setChoiceMode(ListView.CHOICE_MODE_SINGLE);



        lvUsers.setOnItemClickListener(new OnItemClickListener()
        {

            int positionItem;

            public void onItemClick(AdapterView<?> parent, View view,int position, long id)
            {
                Intent pongIntent = new Intent(getApplicationContext(),Trav.class);

                int counId=mListUsers.get(position).id;

                pongIntent.putExtra("response",mListUsers.get(position).p);
                pongIntent.putExtra("responseCounID",counId);

                //Put the position of the choose list inside extra
                positionItem=position;
                pongIntent.putExtra("PositionInListSet",positionItem);

                setResult(Activity.RESULT_OK,pongIntent);

                Log.i("CounID *******************************"," "+counId);
                finish();
            }
         });
    }
}
Deville answered 8/5, 2011 at 6:0 Comment(0)
T
38

Since by default ListViews are set to a selection mode of NONE, in touch mode the setSelection method won't have visual effect.

For keeping the previous selection / visually display an explicit selection, first you must set your listview's choice mode appropriately:

listview.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

It's useful to read the API Docs of these methods:

  • setSelection
void android.widget.AdapterView.setSelection(int position)

Sets the currently selected item. To support accessibility subclasses that override this method must invoke the overriden super method first.

Parameters:
position Index (starting at 0) of the data item to be selected.

  • setChoiceMode
void android.widget.ListView.setChoiceMode(int choiceMode)

Defines the choice behavior for the List. By default, Lists do not have any choice behavior (CHOICE_MODE_NONE). By setting the choiceMode to CHOICE_MODE_SINGLE, the List allows up to one item to be in a chosen state. By setting the choiceMode to CHOICE_MODE_MULTIPLE, the list allows any number of items to be chosen.

Parameters:
choiceMode One of CHOICE_MODE_NONE, CHOICE_MODE_SINGLE, or CHOICE_MODE_MULTIPLE

In case this is not enough (say you'd like to always show the last selection differently beside the current selection), you should store your last selected item (a data which populates the ListAdapter) as lastSelectedItem, and in your adapter's getView method assign a different background resource to the renderer if it equals this lastSelectedItem.

If your last selection wouldn't refresh on selection change, you should explicitly call the notifyDataSetChanged method on your adapter instance.

Update
Since your activity containing the ListView is a child of an activity which waits for this one's result (based on the setResult(Activity.RESULT_OK,pongIntent); part), the initial idea is correct, the last position should be passed through the intent when starting the activity:

selectedListItem = getIntent().getIntExtra("PositionInList", -1);
lvUsers.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
lvUsers.setSelection(selectedListItem);

The ListView.CHOICE_MODE_SINGLE solution would work if you remain in the same activity, but you are finishing it on every itemClick (selection change), that's why the extra data should be passed to the starting Intent.

You can also set the previously selected item's background from your adapter -as mentioned above-, overriding its getView method:

lvUsers.setAdapter(new ArrayAdapter(this, R.id.counlistView, groups)
{
    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        final View renderer = super.getView(position, convertView, parent);
        if (position == selectedListItem)
        {
            //TODO: set the proper selection color here:
            renderer.setBackgroundResource(android.R.color.darker_gray);
        }
        return renderer;
    }
});
Thirtytwomo answered 8/5, 2011 at 6:37 Comment(8)
It ok that is going to be the same color because when the user have selected the old selection need to disappear what i went is just before he choose the old choice will be highlightDeville
If you would like to keep the selection until a new item is selected, setting the choice mode of your listview to CHOICE_MODE_SINGLE is enough.Thirtytwomo
inside your activity's onCreate method you should set the listview.setChoiceMode(ListView.CHOICE_MODE_SINGLE);, and you don't even need to set the selection explicitly (listview.setSelection(position);). If it doesn't work, please share your code, to help us detect where the problem is rooted. thank you.Thirtytwomo
Thanks for the code, it made things clearer: it is important, that you finish this activity when selection changes. If the previously selected item's position is passed correctly between intents, the update part of my answer should work for you.Thirtytwomo
Hello! Do you know how to get The same result with using stateListDrawable as background? It seems that if I use view.setSelected(true) - it has no effectSamuels
You could write your own custom component (View extension) for item renderer, and add a new attr to it (e.g. force_selected type="boolean"). Then you must merge it with the current drawable state of the component, and in your state list drawable define the rules for the true/false value of it.Thirtytwomo
Thank you for your code !! combined with Yeung comment below : if (position == selectedListItem) {...} else {...} to reinitialize the view, it works flawlessly. It avoids having to create a whole instance of an ArrayAdapter only to color a single line on a simple adapter !Cartier
Custom Adapater code works like a charm, just add else block to your code.Gusman
M
28

Just:

  1. Set the correct choice mode in your list view. setChoiceMode
  2. Set a background to support the selection state in you item layout, like:

    android:background="?android:attr/activatedBackgroundIndicator"
    

FYI:

Merca answered 19/6, 2013 at 19:10 Comment(4)
Thank a lot. :-) I missed the #2 and was messing with the code for a long time.Associate
for xml setting, you can set android:choiceMode="singleChoice", developer.android.com/reference/android/widget/…Trengganu
After trying lots of solution. I can say this is the best among them.Abhor
Worked for me as well.Stroller
U
16

It's much easier to implement this in your layout files and let Android handle the rest...

1) Make sure you have android:choiceMode="" set on your ListView layout (singleChoice, multipleChoice, etc). By default it is set to none.

<ListView
    android:id="@+id/invite_friends_fragment_contacts_list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:choiceMode="multipleChoice"/> <!-- THIS LINE -->

2) Create a state selector XML file and save it in your drawables folder. In this example, we'll name it state_selector.xml:

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

3) In your list item layout, add the state_selector.xml file as the background:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/state_selector">  <!-- THIS LINE -->

    <!-- ALL OF YOUR ELEMENTS WILL GO HERE (TextViews, ImageViews, etc) -->

</RelativeLayout>

If you are using multipleChoice, you can override onItemClick()and set/unset selected items accordingly. Android will change the background color as specified in your state_selector.xml file.

Undergird answered 15/8, 2014 at 6:49 Comment(2)
For me, the magic line was android:state_activated="true" and I didn't need android:state_selected. THANK YOU!Transfer
thanks, this way I can put custom color, though "?android:attr/activatedBackgroundIndicator" works.Vicissitude
D
9

I had a problem finding an easy solution to this because so many tutorials and answers contained information on single select via radio buttons (Which relied heavily on RadioGroup's).

My problem was that I could set the item to my "Highlighted" state but then couldn't reset the list when the next item was selected. Here is what I came up with:

listView.setOnItemClickListener(new ItemHighlighterListener ());

With this class:

private class ItemHighlighterListener implements OnItemClickListener{

    private View lastSelectedView = null;

    public void clearSelection()
    {
        if(lastSelectedView != null) lastSelectedView.setBackgroundColor(android.R.color.transparent);
    }

    @Override
    public void onItemClick(AdapterView<?> arg0, View view, int arg2, long arg3) {
        clearSelection();
        lastSelectedView = view;
        view.setBackgroundDrawable(view.getContext().getResources().getDrawable(R.drawable.shape_selected_menu_item));
    }
}
Derris answered 24/8, 2011 at 14:35 Comment(0)
R
4

I solve this problem in the following way: 1. set a lastClickId, when click the item in listView, update the lastClickId to position value, then update the view's background. After this, when we click one item, this item will be highlighted, but when we scroll the listView(make the item which we selected out of the screen) and scroll back, the highlight is gone, because the method getView() rerun in your adapter, so, we have to do the next thing. 2. in your adapter, change the background in the method getView(), here is the code:

private static int lastClickId = -1;
private OnItemClickListener listener = new OnItemClickListener() {

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
            long id) {
        if ((lastClickId != -1) && (lastClickId != position)) {
            parent.getChildAt(lastClickId).setBackgroundResource(
                    R.color.grey);
            view.setBackgroundResource(R.color.blue);
        }
        if (lastClickId == -1) {
            view.setBackgroundResource(R.color.blue);
        }
        lastClickId = position;

    }

};

public static int getCurrentSelectedItemId() {
    return lastClickId;
}

Adapter:

public View getView(int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub

    View view = mInflater.inflate(R.layout.tweet_list_layout, null);
    // set selected item's background to blue
    if (position == MainUserFeedFragment.getCurrentSelectedItemId()) {
        view.setBackgroundResource(R.color.blue);
        }
    }
Rewarding answered 6/12, 2012 at 7:47 Comment(1)
ok. This look quite clear but please be aware that the view may be reuse in listview and no chance to reset the color. Therefore, I suggest in the method getView(), we should add a else case to reset the color. Say else view.setBackgroundResource(R.color.grey);Smokechaser
S
1

Why dont you store the selections in an array, then pass that array in the constructor of the ListView Array Adapter, something like myArrayAdapter(context,layoutID,dataArray,selectionArray)

then in your getView method for the arrayadapter, just do a check. For example in pseudocode

if row was previously selected
    change background color
Somewise answered 8/5, 2011 at 7:46 Comment(0)
O
1

You can use transition. Follow my code because i have achieved highlighting of specific listview item by choice Lets say you want to highlight first item for 5 seconds.

 if(position == 0){
                    viewHolderThubnail.relImage.setBackgroundResource(R.drawable.translate);
                    TransitionDrawable transition = (TransitionDrawable) viewHolderThubnail.relImage.getBackground();
                    transition.startTransition(1000);

                }else{

                    viewHolderThubnail.relImage.setBackgroundResource(R.color.white);
                }

translate.xml

<?xml version="1.0" encoding="UTF-8"?>
   <transition xmlns:android="http://schemas.android.com/apk/res/android">
          <!-- The drawables used here can be solid colors, gradients, shapes, images, etc. -->
          <item android:drawable="@drawable/new_state" />
          <item android:drawable="@drawable/original_state" />
   </transition>

new_state.xml

<?xml version="1.0" encoding="UTF-8"?>
<shape   xmlns:android="http://schemas.android.com/apk/res/android"
            android:shape="rectangle">
    <solid android:color="#92BCE7"/>
</shape>

original_state.xml

<?xml version="1.0" encoding="UTF-8"?>
<shape   xmlns:android="http://schemas.android.com/apk/res/android"
            android:shape="rectangle">
    <solid android:color="#FFFFFF"/>
</shape>

If you understood this code, which is very simple i must say, then the listview item at zero'th position will highlight in blue color for 5 seconds and then it will slow fade to white color.

One answered 29/10, 2013 at 12:9 Comment(0)
S
0

The SIMPLEST of all

View updatedview=null;

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

    //these two lines of code means that only one item can be selected at a time
    if(updatedview != null)
        updatedview.setBackgroundColor(Color.TRANSPARENT);
    updatedview=view;

    Toast.makeText(getApplicationContext(), " " + str[position],Toast.LENGTH_LONG).show();
    view.setBackgroundColor(Color.CYAN);
}
Symposium answered 2/3, 2016 at 17:4 Comment(1)
When the user scrolls, this would create problems, unless the background color is explicitly set/reset for each row. Thus, this ain't a good solutionCookson

© 2022 - 2024 — McMap. All rights reserved.