Android - Keep ListView's item highlighted onc

2020-01-24 11:08发布

So I have an activity with 2 ListView widgets, when you select a value in the first one, the second is populated with values related to the selection in the first ListView. This mechanic works without a problem, but now I want the user choices to stay highlighted. I've read a good ammount of question related to this topic and it seems there is a myriad of ways one can accomplish this but after trying about 4-5 of em' I still can't get it to work.

I've got it working on the second ListView using the android:listSelector="#CCCCCC" XML Attribute, but this seems to be wiped clean once a OnItemClickListener is introduced into the mix (like the one I use on my first ListView).

So far here's what I've got:

Custom OnItemClickListener I found browsing various answer regarding this topic (slightly modified it in order for it to load my info the second ListView):

private class ItemHighlighterListener implements OnItemClickListener {

    private View oldSelection = null;

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

    public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
        clearSelection();
        oldSelection = view;
        view.setBackgroundDrawable(view.getContext().getResources().getDrawable(R.drawable.list_selector));
        loadClubs(mXMLPortalOptions.getRegion(pos).getId());
        mClubList.setAdapter(new ArrayAdapter<String>(getApplicationContext(), R.layout.list_item_white, mClubs));
    }
}

Here's my list_selector.xml file :

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_selected="true"><shape>
            <solid android:color="#CCCCCC" />
        </shape></item>

    <item android:state_selected="false"><shape>
            <solid android:color="#FFFFFF" />
        </shape></item>

</selector>

The method (OnItemClick) is called and executed, but the background of my ListItem stays the same color :/

I can't believe that this simple task has proven so complicated.

If I have omitted code that could be useful or if my question is lacking details, feel free to point that out and I'll do my best to explain myself.

11条回答
不美不萌又怎样
2楼-- · 2020-01-24 11:34

If you can use a drawable for displaying listItem Highlighted then you should use following code:-

listView.setSelector(R.drawable.bg_image);

It works.

查看更多
戒情不戒烟
3楼-- · 2020-01-24 11:36

There is simple fully-XML solution, which worked for me. Firstly, define XML-drawable with selector code in which "normal" state will correspond to "selected unpressed" visual state of a list item, and state_pressed=true to "pressed" visual state. Example of file "custom_item_selector.xml", resembling Holo blue selection:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <solid
                android:color="#643292ff">
            </solid>
            <stroke
                android:width="1dp"
                android:color="#c83292ff">
            </stroke>
        </shape>
    </item>
    <item>
        <shape android:shape="rectangle">
            <solid
                android:color="#323292ff">
            </solid>
            <stroke
                android:width="1dp"
                android:color="#783292ff">
            </stroke>
        </shape>
    </item>
</selector>

(may also set focused state there). Secondly, apply this xml-drawable as ListView's listSelector and set it's desired choiceMode:

<ListView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/listView"
            android:choiceMode="singleChoice"
            android:listSelector="@drawable/custom_item_selector"/>

That's all. It allows to define different visual states for "simply selected" and "pressed selected" items, for example making items brighter on press.

查看更多
兄弟一词,经得起流年.
4楼-- · 2020-01-24 11:43

I faced similar problem. That's my solution:

First add custom list selector to your list view:

<ListView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:listSelector="@drawable/listselector" />

Inside listselector.xml:

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

And finally a drawable bg.xml with color of your highlight:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#33b5e6"/>
</shape>
查看更多
倾城 Initia
5楼-- · 2020-01-24 11:48

To summarize this post and maybe help someone else in future I suggest the answer :)

First, we need to create res/drawable/list_item_background.xml file with the following contents:

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

Specify your drawable resources, of course. And you can also add other <item> elemens with different states like state_pressed, state_focused etc.

Then, we should set the background parameter to our custom list item ViewGroup element (f.i. res/layout/list_item_layout.xml) like this:

android:background="@drawable/list_item_background"

The next step is modifying our custom Adapter class. Here is the following code fragment:

public class CustomAdapter extends BaseAdapter {
    private List<Item> items;
    private LayoutInflater itemInflater;        
    private int selectedIndex; // add this

    public CustomAdapter(Context c, List<Item> items) {
        this.items = items;
        this.itemInflater = LayoutInflater.from(c);
        selectedIndex = -1; // add this
    }

    /* add this */
    public void setSelectedIndex(int index) {
        selectedIndex = index;
        notifyDataSetChanged();
    }

    /* other adapter's stuff */

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView == null) {
            convertView = itemInflater.inflate(R.layout.list_item_layout, parent, false);
        }

        // add this
        convertView.setActivated(selectedIndex != -1 && position == selectedIndex);

        /* do some stuff */

        return convertView;
    }
}

Finally, we should call the setSelectedIndex(position) adapter's method in onItemClick(...) method of AdapterView.OnItemClickListener.

public class YourActivity extends Activity
        implements AdapterView.OnItemClickListener {

    private CustomAdapter mCustomAdapter;

    /* activity implementation */

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

Now, we can be satisfied with proper list items highlighting :)

P.S. If we want to enable multiple choice mode on our list we'll just place the following string to our activity class where listView instance is kept:

listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

Thus, we'll get proper multiple items highlighting.

-- Hope this helps anyone :)

查看更多
ゆ 、 Hurt°
6楼-- · 2020-01-24 11:51

lv.setSelector(R.drawable.highlighter);

put a highlighter.png image in drawable folder
simplest way to highlight selected item in list view.

查看更多
小情绪 Triste *
7楼-- · 2020-01-24 11:52

To expand on Shaiful's great solution, you might not get his to work in your situation.

If you are using have your code all in public void onListItemClick(ListView l, View v, int index, long id), if you're using fragments and have to declare an interface instead of implementing OnListItemClickListener, or whatever is causing your IDE to generate errors, you might have to access variables and methods statically.

public static int selectedPosition = 0;
ArrayAdapter<Your_obj> adapter = null;

@Override
public void onListItemClick(ListView l, View v, int index, long id) {
    super.onListItemClick(l, v, index, id);

        selectedPosition = index;
        Your_adapter.setSelectedIndex(selectedPosition);
        adapter.notifyDataSetChanged();
}

And in Your_adapter:

private static int selectedIndex;

//public Your_adapter...

public static void setSelectedIndex(int ind) {
    selectedIndex = ind;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    WellHolder holder = null;

    if (null == convertView) {

                //set up your "holder"
    }

    if (position == selectedIndex) {
        convertView.setBackgroundColor(convertView.getResources().getColor(R.color.cyan));
    }
    else {
        convertView.setBackgroundColor(convertView.getResources().getColor(R.color.silver));
    }

    return convertView;
}

Some other differences are that you don't have to initialize any variables as "0" or "-1" and notifyDataSetChanged() is called in your activity.

Once again, thanks for your solution @Shaiful. It certainly helped save me time trying to get what is default in iOS to work for Android, all while avoiding selector/item/focused/pressed/etc.

查看更多
登录 后发表回答