Comment garder onItemSelected de tirer sur un nouvellement instancié Spinner?
J'ai pensé à certains moins que d'élégantes manières de résoudre ce problème, mais je sais que je dois être en manque de quelque chose.
Mon onItemSelected
déclenche immédiatement et sans aucune interaction avec l'utilisateur, et c'est un comportement indésirable. Je souhaite pour l'INTERFACE utilisateur d'attendre jusqu'à ce que l'utilisateur sélectionne quelque chose avant qu'elle ne fasse quoi que ce soit.
J'ai même essayé de la configuration de l'auditeur dans le onResume()
, en espérant que pourrait l'aider, mais il ne le fait pas.
Comment puis-je arrêter ce tir hors tension avant que l'utilisateur peut toucher le plus de contrôle?
public class CMSHome extends Activity {
private Spinner spinner;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Heres my spinner ///////////////////////////////////////////
spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.pm_list, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
};
public void onResume() {
super.onResume();
spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
}
public class MyOnItemSelectedListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
Intent i = new Intent(CMSHome.this, ListProjects.class);
i.putExtra("bEmpID", parent.getItemAtPosition(pos).toString());
startActivity(i);
Toast.makeText(parent.getContext(), "The pm is " +
parent.getItemAtPosition(pos).toString(), Toast.LENGTH_LONG).show();
}
public void onNothingSelected(AdapterView parent) {
//Do nothing.
}
}
}
- Vous pouvez regarder cette solution, c'est simple et pratique. stackoverflow.com/a/10102356/621951
- Une solution simple serait de faire le premier élément de
Spinner
vide et l'intérieur deonItemSelected
vous pouvez détecter si la Chaîne n'est pas vide, alorsstartActivity
! - Ce modèle fonctionne correctement stackoverflow.com/questions/13397933/...
Vous devez vous connecter pour publier un commentaire.
Je me serais attendu à votre solution de travail, j'ai bien l'événement de sélection ne serait pas de feu si vous définissez l'adaptateur avant l'installation de l'auditeur.
Cela étant dit, un simple indicateur booléen vous permettra de détecter les voyous de la première sélection de l'événement et de l'ignorer.
onResume()
etonPostResume()
, de sorte que tous les normales crochets ont achevée au moment de la mise en page qui se passe.mSpinner.setSelection(0, false);
et configurer l'auditeur. J'espère que cela fonctionne.OnItemSelected
de rappel à chaque fois qu'il est lancé en réponse àsetSelection
, et cette question ne parle que de la première fois c'est au cours de la première disposition de l'INTERFACE utilisateur du processus. Dans ce but, votre solution est la meilleure. Celui que j'ai fait est plus universel, mais peut-être pas fiable, dans l'avenir, même si je m'attends à ce qu'il dure très longtemps. Cependant, une allusion à une réponse n'est toujours pas vraiment une réponse, si vous me demandez.Spinner
n'est pas particulièrement bien conçu widget à l'égard de cette question. Si vous avez besoin de contrôler la mise en œuvre, voir dans la troisième partie de remplacements.setOnItemSelectedListener()
sera "Enregistrer un rappel à être invoquée lorsqu'un élément dans cette AdapterView a été sélectionné." developer.android.com/guide/topics/ui/controls/spinner?hl=en dit aussi: "Lorsque l'utilisateur sélectionne un élément dans la liste déroulante, le Spinner objet reçoit un élément sélectionné à l'événement."Spinner
. Je voudrais vous attendez pas à le casser, tout comme je ne m'attends pas à sortir de l'hypothèse que ma réponse fait. Mais, des trucs qui se passe.Spinner
n'est pas un bon choix de widget. 🙂L'utilisation de Runnables est complètement incorrect.
Utilisation
setSelection(position, false);
dans la sélection initiale avantsetOnItemSelectedListener(listener)
De cette façon, vous définissez votre sélection avec pas d'animation qui provoque l'élément sélectionné auditeur à être appelé. Mais l'auditeur est nulle donc, rien n'est exécuté. Ensuite, votre écouteur est attribué.
Afin de suivre cette séquence exacte:
position
?position
doit être la valeur qui vient de [votre auditeur](developer.android.com/reference/android/widget/...?>, android.vue.Vue, int, long))s.setSelection(position, false);
Réglage animer la valeur false est le tour est joué. Pas de piratage! Propre solution.s.setSelection(position, false);
doit être appelée après le réglage de l'adaptateur.Se référant à la réponse de Dan Dyer, essayez d'enregistrer le
OnSelectListener
dans unpost(Runnable)
méthode:Par le fait que pour moi, le comportement souhaité finalement eu lieu.
Dans ce cas, il signifie également que l'auditeur ne se déclenche sur un élément modifié.
onCreate()
,onResume()
etc. Dans ce cas, c'est un truc fantastique, sans danger d'condition de course. J'ai l'habitude d'utiliser cette astuce dansonCreate()
juste après la mise en page de code.J'ai créé un petit utilitaire méthode pour changer
Spinner
sélection sans en avertir l'utilisateur:Il désactive l'auditeur, les changements de la sélection, et re-permet à l'auditeur d'après.
Le truc, c'est que les appels asynchrones pour le thread d'INTERFACE utilisateur, de sorte que vous avez à faire dans consécutives gestionnaire de messages.
setSpinnerSelectionWithoutCallingListener
deux fois plus rapidement, de sorte que le deuxième appel est effectué alors que le premier a déjà mis à l'auditeur denull
, votre compteur s'être coincé avec unnull
auditeur à jamais. Je propose le correctif suivant: ajouterif (listener == null) return;
aprèsspinner.setSelection(selection)
.Malheureusement, il semble que les deux plus couramment proposé des solutions à ce problème, à savoir le comptage de rappel occurrences et l'affichage d'un Exécutable pour définir la fonction de rappel à une date ultérieure peut à la fois d'échouer lorsque, par exemple, les options d'accessibilité sont activés. Voici une classe d'assistance qui fonctionne autour de ces questions. En outre explenation est dans le bloc de commentaire.
J'ai eu BEAUCOUP de problèmes avec la casserole de cuisson de quand je ne le veux pas, et ici toutes les réponses ne sont pas fiables. Ils travaillent, mais parfois seulement. Vous allez finir par courir dans les scénarios où ils échoueront et introduire des bugs dans votre code.
Ce qui a fonctionné pour moi a été de stocker le dernier index sélectionné dans une variable et l'évaluer dans l'écouteur. Si c'est le même que le nouvel indice choisi de ne rien faire et de retour, d'autre continue avec l'auditeur. Ce faire:
Croyez-moi quand je dis cela, c'est de loin la solution la plus fiable. Un hack, mais ça fonctionne!
onItemSelected
j'ai vérifié récemment, à chaque fois que vous modifiez la sélection de la toupieJ'ai été dans une situation similaire, et j'ai une solution simple de travailler pour moi.
Il semble que les méthodes de
setSelection(int position)
etsetSelected(int position, boolean animate)
ont différentes internes de mise en œuvre.Lorsque vous utilisez la deuxième méthode
setSelected(int position, boolean animate)
avec de faux animer drapeau, vous obtiendrez la sélection sans cuissononItemSelected
auditeur.setSelection(int position, boolean animate);
onItemSelected
dans API23Juste pour de la chair des conseils à l'aide de la onTouchListener à la distinction entre les appels automatiques vers le setOnItemSelectedListener (qui font partie de l'Activité de l'initialisation, etc.) vs appels à elle est déclenchée par des interactions avec l'utilisateur, je n'ai la suite, après avoir essayé quelques autres suggestions ici et trouvé qu'il a bien travaillé avec le moins de lignes de code.
Venez de définir un champ Booléen pour votre Activité/Fragment comme:
Puis juste avant de fixer votre spinner est setOnItemSelectedListener, définir une onTouchListener:
Après tirant sur mes cheveux pendant un long moment maintenant, j'ai créé ma propre Spinner classe. J'ai ajouté une méthode qui se déconnecte et se connecte à l'auditeur de façon appropriée.
L'utiliser dans votre XML comme ceci:
Tout ce que vous avez à faire est de récupérer l'instance de SaneSpinner après l'inflation et de l'appel de la sélection comme ceci:
Avec cela, aucun événement est déclenché et l'interaction de l'utilisateur n'est pas interrompu. Cela réduit mon code de la complexité beaucoup. Cela devrait être inclus dans le stock Android car il est vraiment un pain PITA.
Pas d'événements indésirables à partir de la mise en page de phase si vous vous en remettez l'ajout de l'écouteur jusqu'à la mise en page est terminée:
ViewTreeObserver.OnGlobalLayoutListener
sur les versions ci-dessous J en appelantViewTreeObserver.removeGlobalOnLayoutListener
, qui est obsolète et a un nom similaire à la méthode de cette réponse utilise.Ce sera le cas si vous effectuez la sélection en code;
Au lieu de déclaration ci-dessus l'utilisation
Edit: Cette méthode ne fonctionne pas pour Mi Android Version Mi de l'INTERFACE utilisateur.
J'ai eu une réponse très simple , sûr à 100% ça marche:
Je l'ai trouvé beaucoup plus solution élégante à ce. Il consiste à compter combien de fois le ArrayAdapter (dans votre cas, "la carte")a été invoquée. Disons que vous avez 1 spinner et que vous appelez:
Déclarer int compteur après le onCreate et puis à l'intérieur de onItemSelected() la méthode à mettre un "si" condition pour vérifier combien de fois le atapter a été appelé. Dans votre cas, vous l'avez appelé tout à la fois si:
Ma petite contribution, est une variation sur certains de ce qui précède que l'a faite pour moi un peu de temps.
Déclarer une variable de type entier comme valeur par défaut (ou la dernière valeur utilisée enregistrés dans les préférences).
Utilisation spinner.setSelection(myDefault) pour définir la valeur avant de l'auditeur est enregistré.
Dans le onItemSelected vérifier si le nouveau spinner valeur est égale à la valeur attribuée avant l'exécution de tout autre code.
Cela a l'avantage de ne pas exécuter du code si l'utilisateur sélectionne la même valeur à nouveau.
Après avoir eu le même problème, je suis venu à cette solutions à l'aide de balises.
L'idée derrière cela est simple: Chaque fois que le compteur est modifié par programmation, assurez-vous que l'étiquette reflète la position sélectionnée. Dans l'écouteur, puis vous vérifiez si la position sélectionnée est égale à la balise. Si c'est le cas, le spinner sélection a été modifié par programmation.
Ci-dessous est mon nouveau "spinner " proxy" de la classe:
Vous aurez également besoin d'un fichier XML avec le tag d'installation dans votre
Values
répertoire.J'ai nommé mon fichier
spinner_tag.xml
, mais c'est à vous de voir.Il ressemble à ceci:
Maintenant remplacer
dans votre code avec
Et faire de votre gestionnaire d'un peu ressembler à ceci:
La fonction
isUiTriggered()
renvoie true si et seulement si le compteur a été changé par l'utilisateur. Notez que cette fonction a un effet secondaire - il définir la balise, donc un deuxième appel dans le même auditeur appel retournera toujoursfalse
.Ce wrapper aussi de gérer le problème avec l'auditeur d'être appelé lors de la présentation de la création.
Avoir du plaisir,
Jens.
Depuis rien n'a fonctionné pour moi, et j'ai plus de 1 spinner, à mon avis (et à mon humble avis, la tenue d'un bool carte est inutile) j'utilise la balise de compter les clics :
Beaucoup de réponses déjà, voici la mienne.
J'étends
AppCompatSpinner
et ajouter une méthodepgmSetSelection(int pos)
qui permet programmatique sélection de la configuration sans déclencher une sélection de rappel. J'ai codé ce avec RxJava de sorte que la sélection des événements sont livrés par desObservable
.Un exemple de son utilisation, appelé dans
onCreateView()
dans unFragment
par exemple:où
setSelection()
est une méthode dans l'affichage de la vue qui ressemble à ça, et qui est appelé à la fois à partir de la sélection de l'utilisateur des évènements via leObservable
et également dans le reste de la programmation, de sorte que la logique de gestion des sélections est commun aux deux méthodes de sélection.Je voudrais essayer d'appeler
après l'appel de setAdapter(). Essayez également de téléphoner avant de l'adaptateur.
Vous avez toujours la solution d'aller avec sous-classement, où vous pouvez l'envelopper d'un indicateur booléen à votre remplacé setAdapter méthode d'ignorer l'événement.
La solution avec un drapeau booléen ou un compteur de ne pas m'aider, parce que pendant le changement d'orientation onItemSelected() appelle la "survole" le drapeau ou le comptoir.
Je sous-classé
android.widget.Spinner
et fait de minuscules ajouts. Les parties pertinentes sont ci-dessous. Cette solution a fonctionné pour moi.Ce n'est pas une solution élégante soit. En fait, c'est plutôt Rube-Goldberg, mais il semble fonctionner. I assurez-vous que le compteur a été utilisé au moins une fois par l'extension de l'adaptateur tableau et surchargeant ses getDropDownView. Dans la nouvelle getDropDownView méthode que j'ai un indicateur booléen qui est configuré pour afficher le menu déroulant a été utilisé au moins une fois. - Je ignorer les appels à l'auditeur jusqu'à ce que le drapeau est réglé.
MainActivity.onCreate():
remplacé adaptateur tableau:
modifié auditeur:
si vous avez besoin de recréer de l'activité à la volée par exemple: changement de thèmes , un simple drapeau/compteur de coutume de travail
utilisation onUserInteraction() pour détecter l'activité de l'utilisateur,
référence : https://stackoverflow.com/a/25070696/4772917
J'ai fait avec la façon la plus simple:
onCreate();
Fait
C'est ma dernière et facile à utiliser la solution :
Utiliser la valeur par défaut
setSelection(...)
pour le comportement par défaut ou utilisersetSelectionWithoutInformListener(...)
pour la sélection d'un élément dans la casserole sans déclencher OnItemSelectedListener de rappel.J'ai besoin d'utiliser
mSpinner
dans ViewHolder, de sorte que le drapeaumOldPosition
est définie dans l'anonymat intérieur de la classe.Je voudrais stocker l'index initial lors de la création de la onClickListener objet.
Ma solution utilise
onTouchListener
mais n'a pas de limite de son utilisation. Il crée un wrapper pouronTouchListener
si nécessaire, lorsque le programme d'installationonItemSelectedListener
.J'ai peut-être répondu trop tard sur le post, mais j'ai réussi à atteindre cet objectif en utilisant Android de liaison de Données de la bibliothèque Android Databinding . J'ai créé une liaison personnalisée à assurez-vous que l'auditeur n'est pas appelé jusqu'à ce que l'élément sélectionné est modifié de sorte que même si l'utilisateur choisit même position plus et plus encore, l'événement n'est pas déclenché.
Mise en page fichier xml
app:position
est l'endroit où vous êtes de passage à la position d'être sélectionné.Liaison personnalisée
Vous pouvez en lire plus sur la coutume de la liaison de données ici Android Personnalisé Setter
NOTE
N'oubliez pas d'activer la liaison de données dans votre Gradle fichier
Inclure vos fichiers de mise en
<layout>
tagsIl n'est pas particulièrement élégant solution, mais je trouve qu'il fonctionne de manière fiable. Il suffit de définir les auditeurs sur un retard de filetage à partir de l'intérieur de onResume. Vous êtes ensuite libre de faire tout d'initialisation que vous aimez, et l'INTERFACE utilisateur pourra alors effectuer toutes les modifications de mise en page, puis définissez les auditeurs.
La conception d'un spinner pour l'usage commun, juste à l'entrée de données et d'obtenir de l'utilisateur choisi, avantages :
1. Garder spinner style même pour app.
2. Début spinner n'importe où.
3. Facile à manipuler lié spinner(démarrer ReuseSpinner à nouveau avec des données différentes).
Mon démo exemple : ReuseSpinner
transmettre des données à ReuseSpinner :
obtenez de l'utilisateur choisi :
Pas un préfet de la solution, mais si votre heureux avec le départ de la chaîne comme une place de titulaire, vous pouvez ajouter un lieu porteur de printemps de la valeur ("Day_of_Work_Out")