Highlight selected item in "ListFragment"?
Asked Answered
H

7

9

I have posted the same problem a couple of times but it hasn't yet been resolved. I have a ListFragment and I want to highlight the selected item in the list. I have been given suggestions to use a "selector". I don't understand how to use this selector. My ListFragment class is:

// Create an adapter with list of stores and populate the list with
        // values
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
                android.R.layout.simple_list_item_1, StoreList);
        setListAdapter(adapter);
        mDbHelper.close();
    }

    /*
     * (non-Javadoc)
     * 
     * Handles the event when an item is clicked on left pane, performs action
     * based on the selection in left pane
     *  
     * @see android.app.ListFragment#onListItemClick(android.widget.ListView,
     * android.view.View, int, long)
     */
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        String selectedStore = (String) getListAdapter().getItem(position);
        DetailFragment fragment = (DetailFragment) getFragmentManager()
                .findFragmentById(R.id.detailFragment);
        if (fragment != null && fragment.isInLayout()) {
            v.setBackgroundColor(getResources().getColor(R.color.BLUE));
            // passes selectedStore to detail fragment  
            fragment.setText(selectedStore);

            // getItemList(selectedStore);

        }

Using setBackground sets the color permanently, but I want it to go away when another item is selected. I understand how to use a selector in a ListView but in my case if I haven't defined any xml for the Listview, then how would I use a "selector"? I am using android.R.layout.simple_list_item_1 which is predefined.

Hallucination answered 26/8, 2012 at 12:50 Comment(1)
The concept of "selection" in Android for a ListView is for use with D-pads, trackballs, arrow keys, and other pointing devices. On tablets, there is a related concept of an "activated" row, designed to highlight the last-tapped-upon item from the touchscreen, to provide context for something adjacent to it (e.g., master-detail pattern).Scouring
H
4

I wasn't getting what I wanted so I kept on digging and came up with a "cheap" solution which might not be the best practice but does the job. I wanted the item to be highlighted when selected and the color should go away when other item is selected from the listFragment. This is what worked for me- I defined a static View V; and initialized it V = new View(getActivity()); Then inside my

onListItemClick(ListView l, View v, int position, long id)

            V.setBackgroundResource(0);
            v.setBackgroundResource(R.color.BLUE);
            V = v;
Hallucination answered 26/8, 2012 at 17:8 Comment(3)
Might even call it bad practice instead of 'not the best practice'; storing a view, which keeps a reference to the activity, in a static object. Thereby leaking the activity.Metameric
You will have a problem when the list grows larger than the screen. Because the same view will be reused for previously hidden items, when they are displayed and thus some of them can be shown "selected".Crosspatch
@Crosspatch I have that problem. Do you know how to fix that? #31442567Zinkenite
N
7

The following worked for me for:

res/color/menu_highlight.xml

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

res/values/colors.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources> 
<color name="white">#FFFFFF</color>
<color name="red">#FF0000</color>
</resources>

res/layout/menuitem.xml:: (XML for every item in the list)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent">
    <TextView
        android:id="@+id/textmenu"
        android:layout_height="wrap_content"
        android:text="text"
        android:textColor="#FFFFFF" 
        android:background="@color/menu_highlight"
        android:visibility="visible"
        android:layout_width="fill_parent" />
</LinearLayout>

Finally, in the ListFragment class, add View previous and add the following code to the onlistitemclick function.. (mentioned in ListFragment: highlight selected row)

public class MenuListFragment extends ListFragment{

View previous;

@Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id); 
       //Logic to highlight selected item
        previous.setSelected(false);
        v.setSelected(true);
        previous=v;
    }

}    
Noon answered 9/7, 2013 at 22:5 Comment(1)
This sounds like it will suffer from the same problem Stefan mentioned on the accepted answer: You will have a problem when the list grows larger than the screen. Because the same view will be reused for previously hidden items, when they are displayed and thus some of them can be shown "selected".Carpet
P
6

From your ListView, call setChoiceMode(ListView.CHOICE_MODE_SINGLE). Then, whenever you want to highlight a selected item, call setItemChecked(index, true).

Panhellenic answered 26/8, 2012 at 12:58 Comment(1)
This is not working if you use custom adapter with custom list item layout.Fairspoken
F
4

I tried the same and I didn't find any good solution. What I actually do is using this code to set the listener:

listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
    public void onItemClick(AdapterView<?> parent, View view, int position, long id){
        list_adapter.setSelectedPosition(position);
        listView.invalidate();
    }
});

where the list adapter defines the following public methods

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View rowView = GuiBuilder.createHeroListItemView(heroes.get(position),getContext(),parent,false);
    if(position == selected_pos){
        rowView.setBackgroundColor((rowView.getResources().getColor(R.color.list_item_selected_color)));
    }
    return rowView;
}

public void setSelectedPosition(int selected_pos){
    this.selected_pos = selected_pos;
}

public int getSelectedPosition(){
    return selected_pos;
}

That is, I change the background of the list item programmatically. Moreover to avoid the blinking effect when clicking the list element I don't define any selector for the pressed state

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true"
        android:drawable="@drawable/list_item_focused_color" />
    <item android:drawable="@drawable/list_item_default_color" />
</selector>

This works as intended for me. I didn't find any better solution since setSelected(true) doesn't work on list items!

Fornax answered 26/8, 2012 at 15:13 Comment(1)
It looks fine, will try this out and let you know what I found.Hallucination
H
4

I wasn't getting what I wanted so I kept on digging and came up with a "cheap" solution which might not be the best practice but does the job. I wanted the item to be highlighted when selected and the color should go away when other item is selected from the listFragment. This is what worked for me- I defined a static View V; and initialized it V = new View(getActivity()); Then inside my

onListItemClick(ListView l, View v, int position, long id)

            V.setBackgroundResource(0);
            v.setBackgroundResource(R.color.BLUE);
            V = v;
Hallucination answered 26/8, 2012 at 17:8 Comment(3)
Might even call it bad practice instead of 'not the best practice'; storing a view, which keeps a reference to the activity, in a static object. Thereby leaking the activity.Metameric
You will have a problem when the list grows larger than the screen. Because the same view will be reused for previously hidden items, when they are displayed and thus some of them can be shown "selected".Crosspatch
@Crosspatch I have that problem. Do you know how to fix that? #31442567Zinkenite
U
3

This worked very nice for me in the ListFragment, but I think it works only for Android 4.0 and up. I created a simple layout for the list item with android:background="?android:attr/activatedBackgroundIndicator (in case of Android below 4.0 you need to ceate the similar one in drawables):

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:background="?android:attr/activatedBackgroundIndicator"
android:orientation="horizontal" >

<TextView
    android:id="@+id/list_item_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:ellipsize="end"
    android:singleLine="true"
    android:textAppearance="?android:attr/textAppearanceListItemSmall"
    android:gravity="center_vertical"
    android:layout_margin="@dimen/double_view_margin" />

And then, just create a simple ArrayAdapter using this layout and set the choice mode to single:

final ArrayAdapter<String> labelsAdapter = new ArrayAdapter<String>(getActivity(), R.layout.item_simple_list_item, R.id.list_item_text, labels);

setListAdapter(labelsAdapter);

getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);

After that you can hightlight the necessary item with setItemChecked method:

@Override
public void onListItemClick(final ListView l, final View v, final int position, final long id) {
    getListView().setItemChecked(position, true);
}
Unconventionality answered 24/9, 2014 at 18:31 Comment(1)
If you don't override onListItemClick, then the ListFragment will automatically set that item as checked. Or just make sure to call super.onListItemClick(...).Aguilar
I
0

i code

getListView().setItemChecked(0, true); 

after

setListAdapter(oAdapter);

code block

Inmesh answered 13/10, 2013 at 20:10 Comment(0)
D
0

Something similar to type-a1pha but with the selectors, once you have the view you can view.setSelected(true) and that would add the style you have defined on your selector. you need to remove the flag once the action is performed.

Deferral answered 27/12, 2013 at 18:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.