web-dev-qa-db-fra.com

Android ListView setSelection () ne semble pas fonctionner

J'ai une ListActivity qui implémente onListItemClick() et appelle une fonction doSomething() de la classe. Ce dernier contient l.setSelection(position)l est l'objet ListView.

Il existe maintenant un onClickListener() à l'écoute d'un clic de bouton qui exécute certaines actions et qui appelle aussi doSomething().

Dans le premier cas, l'élément sélectionné est correctement positionné, mais dans le second, rien ne se passe.

Des indices sur ce comportement étrange et comment je pourrais le faire fonctionner?

65
alkar

vous avez peut-être besoin d'utiliser la fonction:

ListView.setItemChecked(int position, boolean checked);
101
meizilp

utiliser requestFocusFromTouch() avant d'appeler la méthode setSelection()

65
AlexD

Je sais que c'est une vieille question mais je viens d'avoir un problème similaire que j'ai résolu de cette manière:

mListView.clearFocus();
mListView.post(new Runnable() {
    @Override
    public void run() {
        mListView.setSelection(index);
    }
});
31
mr_hyde

Vous devrez peut-être insérer setSelection() dans une posted Runnable ( reference ).

15
kostmo

setSelection() n'a pas nécessairement d'impact visuel. La barre de sélection ne s'affiche que si vous utilisez le D-pad/la boule de commande pour parcourir la liste. Si vous appuyez sur l'écran pour cliquer sur quelque chose, la barre de sélection apparaît brièvement et disparaît.

Par conséquent, setSelection() n'aura un impact visuel que si l'activité n'est pas en mode tactile (c'est-à-dire, la dernière chose que l'utilisateur a faite a été d'utiliser le D-pad/le trackball).

Je ne suis pas sûr à 100% que cela explique votre phénomène au vu de la description que vous avez fournie, mais je me suis dit que ça en valait la peine ...

13
CommonsWare

Si vous utilisez un adaptateur pour votre liste, ajoutez ce code à votre adaptateur:

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

}

Dans votre activité:

myAdapter.setSelectedItem(1);
6
Bobs

J'ai une très grande demande avec Webcontent. Lorsque j'ai utilisé le code dans onCreateView, Listview n'était même pas fini de charger .. .. Je l'ai mis dans onPostExecute de mon 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);
                }
            });
        }

N'oubliez pas de définir l'élément enregistré sur Click;)

4
Nick

Pour moi appeler

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

et alors

 listView.setSelection(position);

résolu le problème.

si vous faites cela dans un exécutable, cela fonctionne sans appeler requestFocusFromTouch (), mais l'ancienne position de ListView est affichée pendant un sekound.

2
MaInStReAm

Peut-être devriez-vous utiliser la méthode smoothScrollToPosition (int position) de ListView

2
TaoZang

Lorsqu’on utilise post to setSelection(), la ListView sera affichée en premier, puis fera défiler jusqu’à la position, grâce à " layout ", puis layout agira en réalité sur le setSelection(), car setSelection() appelle le setSelectionFromTop(int position, int y).

listView.setAdapter(listView.getAdapter());
listView.setSelection(123);
0
Sober reflection

Essayez simplement ce code

  listView.setAdapter(adapter);
  listView.setSelection(position);
  adapter.notifyDataSetChanged(); 
0
Cecil Paul

J'ai constaté que parfois setSelection ne fonctionnait pas car je définissais l'attribut "Android: height" de listView sur "wrap_content".

Et les fois où mon application ne fonctionne pas, c’est lorsque listView devient défilable de non-scrollable.

Par exemple, si mon application est "Application de navigateur de fichiers". Lorsque ma liste est inférieure à, disons 6, elle ne peut pas défiler. Maintenant, je reviens au répertoire parent qui contient 11 objets. Je souhaite définir la sélection sur une position et cela ne fonctionnera pas ici.

to\from    |    Scrollable  | non-Scrollable

Scrollable | O | O (bien sûr)

non-scrollable | X | O (bien sûr)

Je ne veux pas utiliser post (Runnable), car il y aura un délai.

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

Réponse:

Vous pouvez essayer de définir "Android: height" sur "match_parent"

Mon dieu, ça passe trois jours.

0
魏經軒

Dans mon cas, smoothScrollToPosition (int position) a fonctionné. Pouvez-vous également me dire comment définir cette position de défilement au centre de la liste? Il est apparu au bas des éléments visibles. 

0
Bhaumik

Pour moi, cela a aidé à définir
ListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); ou ListView.CHOICE_MODE_MULTIPLE
puis
ListView.setSelection(position) ou ListView.setItemChecked(position, true);
.__ fonctionne bien

0
Lemberg

Vous pouvez essayer 2 façons comme celles-ci:
Solution A:

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

Dans certaines situations compliquées, cette solution apportera de nouveaux problèmes dans Android 8.x.
En outre, cela pourrait provoquer une inFocusChange () inattendue. 

Solution B: Définir une vue personnalisée étend ListView. Remplacez la méthode handleDataChanged (). Puis setSelection (0). Dans 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();
}

En activité:

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

Ok, c'est fini.

0
Courysky

J'ai trouvé une solution dans mon cas. Je n'utilise pas Runnable car ma classe étend ListFragment. Ce que je devais faire est de rendre mon index final; Final index = 5; MListView.setSelection (index);

0
DevfoMobile