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?
Androider, I have found a solution for this problem and posted it here (with code sample):
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);
Fragment
's state. –
Oversew 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) {
}
});
isLoaded
as that made more sense than a counter –
Cubbyhole 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.
Androider, I have found a solution for this problem and posted it here (with code sample):
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 }
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.
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!
TAG_INITIALIZING="";
(or any other object) and then to compare with `` if (parentView.getTag() == TAG_INITIALIZING) {parentView.setTag(null);return;}`` –
Dread 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.
setOnItemSelectedListener()
will "Register a callback to be invoked when an item in this AdapterView has been selected." One could argue that an item in the adapterview gets selected internally during initialization, but that's not clear, intuitive, nor guaranteed from what the doc says. –
Magdala 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 :-)
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...
}
}
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());
}
}
}
You should do like this.The sequence is the key.
spinner.setAdapter(adapter);
spinner.setSelection(position);
spinner.setOnItemSelectedListener(listener);
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
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
}
}
The issue is that we are setting listener before the spinner has done rendering. And once it renders, it does select it's datasets 1st option automatically (which is fine), but that causes our listener to trigger.
The solution is to wait for the specific spinner to be laid out, and only then set the listener:
binding.spinnerLanguage.post( new Runnable() {
@Override
public void run() {
binding.spinnerLanguage.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
GeneralUtils.log(TAG, "finally, not triggering on initial render");
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
});
This is the Kotlin version of Andres Q's answer with some improvements.
Anonymous interface implementation:
val listener = object : AdapterView.OnItemSelectedListener, OnTouchListener
{
var userSelect: Boolean = false
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
)
{
if (userSelect)
{
// Your selection handling code here
userSelect = false
}
}
override fun onNothingSelected(parent: AdapterView<*>?)
{
//nothing to do
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(view: View?, event: MotionEvent?): Boolean
{
if (event?.action == MotionEvent.ACTION_DOWN)
{
userSelect = true
}
return false
}
}
Then, Set the listener to the spinner as both an OnItemSelectedListener and an OnTouchListener:
aSpinner.setOnTouchListener(listener)
aSpinner.onItemSelectedListener = listener
© 2022 - 2024 — McMap. All rights reserved.