alkar
alkar

Reputation: 5511

Android ListView setSelection() does not seem to work

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?

Upvotes: 67

Views: 88851

Answers (17)

Courysky
Courysky

Reputation: 331

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.

Upvotes: 2

Cecil Paul
Cecil Paul

Reputation: 643

Simply try this code

  listView.setAdapter(adapter);
  listView.setSelection(position);
  adapter.notifyDataSetChanged(); 

Upvotes: -1

Xavier
Xavier

Reputation: 127

For me the solution to this problem was:

listView.clearChoices();

Upvotes: -1

Nick
Nick

Reputation: 135

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 ;)

Upvotes: 4

Sober reflection
Sober reflection

Reputation: 1

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);

Upvotes: 0

魏經軒
魏經軒

Reputation: 17

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.

Upvotes: 0

MaInStReAm
MaInStReAm

Reputation: 57

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.

Upvotes: 4

DevfoMobile
DevfoMobile

Reputation: 91

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);

Upvotes: 0

mr_hyde
mr_hyde

Reputation: 505

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);
    }
});

Upvotes: 39

Roman Nazarevych
Roman Nazarevych

Reputation: 7703

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

Upvotes: 0

Bhaumik
Bhaumik

Reputation: 61

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.

Upvotes: 0

TaoZang
TaoZang

Reputation: 1690

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

Upvotes: 2

Bob
Bob

Reputation: 23000

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);

Upvotes: 7

AlexD
AlexD

Reputation: 705

use requestFocusFromTouch() before calling setSelection() method

Upvotes: 68

meizilp
meizilp

Reputation: 3921

maybe you need to use function:

ListView.setItemChecked(int position, boolean checked);

Upvotes: 107

kostmo
kostmo

Reputation: 6340

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

Upvotes: 17

CommonsWare
CommonsWare

Reputation: 1006539

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...

Upvotes: 13

Related Questions