I have a spinner which I am showing in a dialog view, and the moment the dialog starts onItemSelected
is called. I don't really want to process this but only when user makes the selection. So I either need to prevent this (maybe because no default value is set?), or I need to know it is not the user that is making this selection?
问题:
回答1:
Androider, I have found a solution for this problem and posted it here (with code sample):
Spinner onItemSelected() executes when it is not suppose to
回答2:
Another option in the spirit of Bill Mote's solution is to make the OnItemSelectedListener
also an OnTouchListener
. The user interaction flag can then be set to true in the onTouch method and reset in onItemSelected()
once the selection change has been handled. I prefer this solution because the user interaction flag is handled exclusively for the spinner, and not for other views in the activity that may affect the desired behavior.
In code:
Create your listener for the 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;
}
}
}
Add the listener to the spinner as both an OnItemSelectedListener
and an OnTouchListener
:
SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);
回答3:
You can simply add an int count to solve it :)
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) {
}
});
回答4:
Beginning with API level 3 you can use onUserInteraction() on an Activity with a boolean to determine if the user is interacting with the device.
http://developer.android.com/reference/android/app/Activity.html#onUserInteraction()
@Override
public void onUserInteraction() {
super.onUserInteraction();
userIsInteracting = true;
}
As a field on the Activity I have:
private boolean userIsInteracting;
Finally, my 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) {
}
});
As you come and go through the activity the boolean is reset to false. Works like a charm.
回答5:
I have solved this problem a different way as I noticed sometimes the onItemSelected method was called twice on orientation change or sometimes once.
It seemed to depend on the current spinner selection. So a flag or counter didn't work for me. Instead I record the system time in BOTH onResume() and onCreate using widgetsRestartTime = System.currentTimeMillis()
widgetsRestartTime is declared as a double and as an intance variable.
Now in the onItemSelected() method I check the current time again and subtract widgetsRestartTime from it as follows: if (System.currentTimeMillis() - widgetsRestartTime > 200) { // user triggered event - so this is a real spinner event so process it } else { // system generated event e.g. orientation change, activity startup. so ignore }
回答6:
Yes what you are seeing is correct and is the default behaviour,You cannot prevent this. The OnItemSelected callback is called on initial load. After that initial load it is only triggered whenever user changes selection or if you change the selection from within your code. You can have a indicator which can tell you whether the event was a result of initial load and ignore the first event if you do not want to process it.
回答7:
I had the same problem, and I solved it by remembering the previous selected spinner value. On each onItemSelected call I compare the new value with the previous, and if it's the same I don't process the code further.
回答8:
I had the same problem. But the accepted solution didn't work for me because I have multiple spinners on my form, and some of them are hidden, and when the spinners are hidden, the listener does not fire, so counting is not a solution for me.
I have found another solution though:
- Set a default TAG on spinner while initializing it, in onCreate() of your activity or onCreateView of your Fragment, and before setting the listener
- In the listener, check the tag, if it is present, then delete it and do not execute the code, by returning.
That's it, it works like a charm!
Example in the listener:
if(((String)parent.getTag()).equalsIgnoreCase(TAG_SPINNERVALUE))
{
parent.setTag("");
return;
}
P.S. And this works for the same listener set to multiple spinners!
回答9:
If you also are shopping for an initially unselected Spinner, you can go with
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if(pos != 0) {
pos--;
// your code here
}
}
Since item 0 is never possible to select. Cheers :-)
回答10:
It worked for me,
private boolean isSpinnerInitial = true;
@Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
if(isSpinnerInitial)
{
isSpinnerInitial = false;
}
else {
// do your work...
}
}
回答11:
I also looked for a good solution on the internet but didn't find any that satisfied my needs. So I've written this extension on the Spinner class so you can set a simple OnItemClickListener, which has the same behaviour as a ListView.
Only when an item gets 'selected', the onItemClickListener is called.
Have fun with it!
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());
}
}
}
回答12:
You should do like this.The sequence is the key.
spinner.setAdapter(adapter);
spinner.setSelection(position);
spinner.setOnItemSelectedListener(listener);
回答13:
If you dont mind using a position for promt you can do something like this every time you want to do staff on the spinner. First set selection to the promt:
spinner.setselected(0);
spinner.add("something");
...
And then do something like that when selection happens:
spinner.ItemSelected += (object sender, AdapterView.ItemSelectedEventArgs e) =>
{
if (spinner.SelectedItemPosition != 0)
{
//do staff
}
}
回答14:
You can try to set the spinner using two arguments, like this:
spinner.setSelection(count, false);
So, put this before the set OnItemSelectedListener :
spinner.setSelection(0,false);
You can check more from the developers page:
https://developer.android.com/reference/android/widget/Spinner.html