Android ListView setSelection() does not seem to work
Asked Answered
H

17

67

I have a ListActivity that implements onListItemClick() and calls a doSomething() function of the class. The latter contains l.setSelection(position) where l is the ListView object.

Now there is a onClickListener() listening for a button click that perfoms some actions and that too calls doSomething().

In the first case, the selected item get positioned appropriately, but in the latter, nothing happens.

Any clues about this strange behaviour and how I might make it work?

Hordein answered 18/9, 2009 at 19:12 Comment(0)
L
107

maybe you need to use function:

ListView.setItemChecked(int position, boolean checked);
Latten answered 19/1, 2011 at 13:35 Comment(2)
This should be the answer to the question. Ensure that the listview is set to CHOICE_MODE_SINGLE in the layout XML or in the java via: myList.setChoiceMode(ListView.CHOICE_MODE_SINGLE); and the setItemChecked worked for me, it moved the selection indicator to the item I passed in (unselecting the previous one).Cherokee
ListView.setItemChecked() is not scrolling to the specified position.Quasijudicial
P
68

use requestFocusFromTouch() before calling setSelection() method

Panfish answered 24/8, 2010 at 10:9 Comment(4)
shouldnt be requestFocusFromTouch() after calling setSelection()?Harbard
@pierr Reading JavaDoc of requestFocusFromTouch() I think the order proposed by AlexD is right.Hammel
It didn't. it causes bad effect in the UI. release and getting the focus back hides the suggestion from the keyboard and u need to click again to get it back.Caw
This worked for me, but the ListView item highlights as if the user was holding their finger down on the specified ListView item and as soon as I touch the screen the item is no longer selected (highlighted). Any solutions so that the selection is set by a finger tap and not a hold?Perennial
K
39

I know this is an old question but I just had a similar problem that I solved in this way:

mListView.clearFocus();
mListView.post(new Runnable() {
    @Override
    public void run() {
        mListView.setSelection(index);
    }
});
Kaliningrad answered 19/3, 2014 at 20:44 Comment(6)
Good answer - fixed my problem in a very non-hacky way where most of the others didn't. Vote this up!Vondavonni
I was missing mListView.clearFocus(); Thanks man! Someone Make THIS the answerUnspotted
This is NOT working 100% because the "clear focus", it is working because enough time have elapsed so the webview finished rendering. Put a bigger HTML content and you'll see.Juice
Why to add delay in selectionAngell
This is useful for Listview inside Dialog.Ute
in my case listview.post(()->listview.setSelection(index)) were enoughChirrupy
O
17

You might need to wrap setSelection() in a posted Runnable (reference).

Ossicle answered 4/5, 2010 at 6:55 Comment(0)
D
13

setSelection() does not necessarily have visual impact. The selection bar only appears if you use the D-pad/trackball to navigate the list. If you tap on the screen to click something, the selection bar appears briefly and vanishes.

Hence, setSelection() will only have a visual impact if the activity is not in touch mode (i.e., the last thing the user did was use the D-pad/trackball).

I am not 100% certain this explains your phenomenon given the description you provided, but I figured it is worth a shot...

Deadfall answered 18/9, 2009 at 20:28 Comment(1)
However, the docs state for setSelection(): "If in touch mode, the item will not be selected but it will still be positioned appropriately". And that's what driving me crazy! Could always be a bug though.Hordein
H
6

If you use an Adapter for your ListView add this code to your adapter:

public class MyAdapter extends
        ArrayAdapter<MyClass> {


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            LayoutInflater inflator = (LayoutInflater) getContext()
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            rowView = inflator.inflate(R.layout.my_adapter, null);
        } else {
            rowView = (View) convertView;
        }

        //...

        // set selected item
        LinearLayout ActiveItem = (LinearLayout) rowView;
        if (position == selectedItem)
        {
            ActiveItem
                    .setBackgroundResource(R.drawable.background_dark_blue);

            // for focus on it
            int top = (ActiveItem == null) ? 0 : ActiveItem.getTop();
            ((ListView) parent).setSelectionFromTop(position, top);
        }
        else
        {
            ActiveItem
                    .setBackgroundResource(R.drawable.border02);
        }

    }

    private int selectedItem;

    public void setSelectedItem(int position) {
        selectedItem = position;
    }

}

In your Activity:

myAdapter.setSelectedItem(1);
Hist answered 23/4, 2012 at 8:38 Comment(2)
There is a semantic error with ActiveItem. In the if(position==selectedItem) block, you call it's member function setBackgroundResource, and then in the next line check to see if it is null. Also, is it b/c the root viewgroup of R.layout.my_adapter a LinearLayout the reason for the cast ?Debility
This looks like a pretty bad hack.Suzerainty
P
4

For me calling

listView.notifyDataSetChanged();
listView.requestFocusFromTouch();

and then

 listView.setSelection(position);

solved the issue.

if you do that in a runnable it works without calling requestFocusFromTouch(), but the old position of the ListView is showen for a sekound.

Peculation answered 22/9, 2014 at 9:6 Comment(2)
I think you mean adapter.notifyDataSetChanged();Arvillaarvin
For prevent show old pos if you use Runnable, call setSelection twice: one before post Runnable and second in Runnable.Arkwright
E
4

I have an very large Request with Webcontent. When I used the code in onCreateView the Listview wasnt even finished loading. I put it in onPostExecute of my AsyncTask.

            //Get last position in listview
        if (listView != null && scrollPosition != 0) {
            listView.clearFocus();
            listView.requestFocusFromTouch();
            listView.post(new Runnable() {
                @Override
                public void run() {
                    listView.setItemChecked(scrollPosition, true);
                    listView.setSelection(scrollPosition);
                }
            });
        }

Dont forget to set the item checked in on Click ;)

Entomb answered 5/4, 2016 at 20:38 Comment(0)
D
2

Maybe you should use the smoothScrollToPosition(int position) method of ListView

Duma answered 28/8, 2012 at 8:42 Comment(1)
For me setSelection(int) not worked if user change ListView size by keyboard in <19 API, but this smoothScrollToPosition(int) works, but looks like workaround.Rappel
K
2

You can try 2 ways like these:
Solution A:

    mListView.post(new Runnable() {
        @Override
        public void run() {
            if (null != mListView) {
                mListView.clearFocus();
                mListView.requestFocusFromTouch();
                mListView.setSelection(0);
            }
        }
    });

In some complicated situation, this solution will bring some new problems in Android 8.x.
Besides it may cause unexpected onFocusChange().

Solution B: Define a custom view extends ListView. Override method handleDataChanged().Then setSelection(0). In CustomListView:

@Override
protected void handleDataChanged() {
    super.handleDataChanged();
    if (null != mHandleDataChangedListener){
        mHandleDataChangedListener.onChanged();
    }
}
HandleDataChangedListener mHandleDataChangedListener;

public void setHandleDataChangedListener(HandleDataChangedListener handleDataChangedListener) {
    this.mHandleDataChangedListener = handleDataChangedListener;
}

public interface HandleDataChangedListener{
    void onChanged();
}

In activity:

    mListView.setHandleDataChangedListener(new CustomListView.HandleDataChangedListener() {
        @Override
        public void onChanged() {
            mListView.setHandleDataChangedListener(null);
            mListView.setSelection(0);
        }
    });
    mAdapter.notifyDataSetChanged();

Ok, That's it.

Kape answered 30/7, 2018 at 15:49 Comment(0)
S
0

In my case smoothScrollToPosition(int position) worked, can you also tell me how to set that scrolled position into center of the list. It appeared at the bottom of visible items.

Sclaff answered 27/12, 2012 at 1:4 Comment(1)
you could do parent_width/2 and subtract it from the scroll position.Pieria
D
0

For me it helped to set
ListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); or ListView.CHOICE_MODE_MULTIPLE
then
ListView.setSelection(position) or ListView.setItemChecked(position, true);
works fine

Denture answered 4/2, 2014 at 17:24 Comment(0)
C
0

Found a solution in my case. I am not using a Runnable since my class is extending ListFragment. What I had to do is make my index a final; final index = 5; mListView.setSelection(index);

Capablanca answered 8/5, 2014 at 22:59 Comment(0)
L
0

I found that sometimes setSelection will not work because I set attribute "android:height" of listView to "wrap_content".

And the times my App won't work is that when listView become scrollable from non-scrollable.

For example, if my app is "File Browser App". When my list is less than, let's say 6, then it's non-scrollable. Now I return to the parent directory, and it has 11 objects, and I want to set selection to some position, and it won't work here.

to\from    |    Scrollable  | non-Scrollable

Scrollable | O | O( of course )

non-Scrollable | X | O( of course )

I don't want to use post(Runnable), because there will has delay.

==================================

Answer:

You can try to set "android:height" to "match_parent"

God, it spends three days.

Luminal answered 25/2, 2015 at 8:29 Comment(1)
Hi, does it also have any effect with using layout weight ?Bartell
M
0

When use post to setSelection(), the ListView will see first , then scroll to the position , thank to "魏經軒", then layout actually will effect the setSelection(), because setSelection() call the setSelectionFromTop(int position, int y), there is another way to solve it.

listView.setAdapter(listView.getAdapter());
listView.setSelection(123);
Mullane answered 28/1, 2016 at 13:3 Comment(1)
@ρяσѕρєя K , I am not used to use editor to format my coding.Thank you very much.Mullane
M
-1

For me the solution to this problem was:

listView.clearChoices();
Microreader answered 11/4, 2016 at 11:59 Comment(0)
P
-1

Simply try this code

  listView.setAdapter(adapter);
  listView.setSelection(position);
  adapter.notifyDataSetChanged(); 
Pulpiteer answered 9/3, 2017 at 12:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.