web-dev-qa-db-fra.com

Spinner onItemSelected appelé à tort (sans action de l'utilisateur)

Je montre une boîte de dialogue que je montre dans une vue de dialogue, et le moment où la boîte de dialogue commence onItemSelected est appelée. Je ne veux pas vraiment traiter cela, mais seulement quand l'utilisateur choisit. Donc je dois soit empêcher cela (peut-être parce qu'aucune valeur par défaut n'est définie?), Ou j'ai besoin de savoir que ce n'est pas l'utilisateur qui fait cette sélection?

25
Androider

Androider, j'ai trouvé une solution à ce problème et l'a posté ici (avec un exemple de code): 

Spinner onItemSelected () s'exécute quand ce n'est pas supposé

6

Une autre option dans l'esprit de la solution de Bill Mote est de faire de OnItemSelectedListener également un OnTouchListener. L'indicateur d'interaction utilisateur peut ensuite être défini sur true dans la méthode onTouch et réinitialisé dans onItemSelected() une fois que le changement de sélection a été traité. Je préfère cette solution car l'indicateur d'interaction utilisateur est traité exclusivement pour le cinéaste, et non pour d'autres vues de l'activité pouvant affecter le comportement souhaité. 

Dans du code:

Créez votre auditeur pour le spinner:

public class SpinnerInteractionListener implements AdapterView.OnItemSelectedListener, View.OnTouchListener {

    boolean userSelect = false;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        userSelect = true;
        return false;
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
        if (userSelect) { 
            // Your selection handling code here
            userSelect = false;
        }
    }

}

Ajoutez l'auditeur au cinéaste en tant que OnItemSelectedListener et OnTouchListener:

SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);
41
Andres Q.

Vous pouvez simplement ajouter un compte int pour le résoudre :)

 sp.setOnItemSelectedListener(new OnItemSelectedListener() {
    int count=0;
    @Override
    public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        if(count >= 1){
            int item = sp.getSelectedItemPosition();
            Toast.makeText(getBaseContext(),
                 "You have selected the book: " + androidBooks[item],
                  Toast.LENGTH_SHORT).show();
        }
        count++;
    }


    @Override
    public void onNothingSelected(AdapterView<?> arg0) {
    }
});
21
Günay Gültekin

À partir du niveau 3 de l'API, vous pouvez utiliser onUserInteraction () sur une activité avec un booléen pour déterminer si l'utilisateur interagit avec le périphérique.

http://developer.Android.com/reference/Android/app/Activity.html#onUserInteraction ()

@Override
public void onUserInteraction() {
    super.onUserInteraction();
    userIsInteracting = true;
}

En tant que champ de l'activité, j'ai:

private boolean userIsInteracting;

Enfin, mon spinner:

    mSpinnerView.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> arg0, View view, int position, long arg3) {
            spinnerAdapter.setmPreviousSelectedIndex(position);
            if (userIsInteracting) {
                updateGUI();
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> arg0) {

        }
    });

Au fur et à mesure que vous avancez dans l'activité, le booléen est remis à faux. Fonctionne comme un charme.

8
Bill Mote

J'ai résolu ce problème d'une manière différente car j'ai remarqué que parfois la méthode onItemSelected était appelée deux fois lors du changement d'orientation ou parfois une fois.

Cela semblait dépendre de la sélection actuelle des disques. Donc, un drapeau ou un comptoir ne fonctionnait pas pour moi. Au lieu de cela, j’enregistre l’heure du système dans BOTH onResume () et onCreate en utilisant widgetsRestartTime = System.currentTimeMillis ()

widgetsRestartTime est déclaré en tant que double et variable intance.

Maintenant, dans la méthode onItemSelected (), je vérifie à nouveau l'heure actuelle et en soustrais widgetsRestartTime comme suit: if (System.currentTimeMillis () - widgetsRestartTime> 200) { // événement déclenché par l'utilisateur - il s'agit donc d'un véritable événement spinner. Traitez-le donc } autre { // événement généré par le système, par exemple. changement d'orientation, démarrage d'activité. alors ignore }

4
karl

J'ai eu le même problème. Mais la solution acceptée n'a pas fonctionné pour moi car j'ai plusieurs disques sur ma fiche, dont certains sont cachés. Lorsque les disques sont masqués, l'auditeur ne se déclenche pas. Compter n'est donc pas une solution pour moi.

J'ai trouvé une autre solution quoique:

  1. Définir un tag par défaut sur spinner lors de son initialisation, dans onCreate () de votre activité ou onCreateView de votre fragment, et avant de paramétrer l'écouteur
  2. Dans le programme d'écoute, vérifiez la balise, si elle est présente, puis supprimez-la et n'exécutez pas le code en renvoyant.

Ca y est, ça marche à merveille!

Exemple dans l'auditeur:

        if(((String)parent.getTag()).equalsIgnoreCase(TAG_SPINNERVALUE))
        {
            parent.setTag("");
            return;
        }

P.S. Et cela fonctionne pour le même auditeur réglé sur plusieurs fileurs!

3
XMight

Oui, ce que vous voyez est correct et correspond au comportement par défaut. Vous ne pouvez pas empêcher cela. Le rappel OnItemSelected est appelé lors du chargement initial. Après ce chargement initial, il est uniquement déclenché chaque fois que l'utilisateur modifie la sélection ou si vous modifiez la sélection dans votre code. Vous pouvez avoir un indicateur qui peut vous indiquer si l'événement est le résultat du chargement initial et ignorer le premier événement si vous ne souhaitez pas le traiter. 

3
Veeresh

J'ai eu le même problème, et je l'ai résolu en gardant à l'esprit la valeur précédemment sélectionnée pour la casserole. Sur chaque appel onItemSelected, je compare la nouvelle valeur à la précédente et, si elle est identique, je ne traite plus le code. 

3
Shumoapp

Si vous achetez également un initialement non sélectionné Spinner , vous pouvez aller avec

@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
    if(pos != 0) {
        pos--;

        // your code here
    }
}

Depuis l'élément 0 n'est jamais possible de sélectionner. À votre santé :-)

2
ThomasRS

Cela a fonctionné pour moi

private boolean isSpinnerInitial = true;

@Override
public void onItemSelected(AdapterView<?> parent, View view,
        int position, long id) {

    if(isSpinnerInitial)
    {
        isSpinnerInitial = false;
    }
    else  {
        // do your work...
    }

}
2
karan

Vous devriez faire comme ceci. La séquence est la clé.

spinner.setAdapter(adapter);
spinner.setSelection(position);
spinner.setOnItemSelectedListener(listener);
1
Treesouth

J'ai aussi cherché une bonne solution sur Internet mais n'en ai trouvé aucune qui réponde à mes besoins ... J'ai donc écrit cette extension sur la classe Spinner afin que vous puissiez définir un simple OnItemClickListener ListView. 

OnItemClickListener est appelé uniquement lorsqu'un élément est "sélectionné". 

Aie du plaisir avec ça!

public class MySpinner extends Spinner
{
    private OnItemClickListener onItemClickListener;


    public MySpinner(Context context)
    {
        super(context);
    }

    public MySpinner(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public MySpinner(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    @Override
    public void setOnItemClickListener(Android.widget.AdapterView.OnItemClickListener inOnItemClickListener)
    {
        this.onItemClickListener = inOnItemClickListener;
    }

    @Override
    public void onClick(DialogInterface dialog, int which)
    {
        super.onClick(dialog, which);

        if (this.onItemClickListener != null)
        {
            this.onItemClickListener.onItemClick(this, this.getSelectedView(), which, this.getSelectedItemId());
        }
    }
}
1
Cliffus

Si cela ne vous dérange pas d’utiliser un poste de promt, vous pouvez le faire chaque fois que vous souhaitez recruter du personnel sur la roulette. Première sélection du promt:

spinner.setselected(0);
spinner.add("something");
...

Et puis faites quelque chose comme ça quand la sélection se produit:

spinner.ItemSelected += (object sender, AdapterView.ItemSelectedEventArgs e) => 
            {
                if (spinner.SelectedItemPosition != 0)
                {
                   //do staff
                } 
            }
0
CDrosos

Vous pouvez essayer de définir le compteur en utilisant deux arguments, comme ceci:

spinner.setSelection(count, false);

Donc, mettez ceci avant l'ensemble OnItemSelectedListener:

spinner.setSelection(0,false);

Vous pouvez en savoir plus sur la page des développeurs:

https://developer.Android.com/reference/Android/widget/Spinner.html

0
Carlos Ughini