Android Spinner: obtenga el evento de cambio de elemento seleccionado

407

¿Cómo puede configurar el detector de eventos para un Spinner cuando cambia el elemento seleccionado?

Básicamente, lo que estoy tratando de hacer es algo similar a esto:

spinner1.onSelectionChange = handleSelectionChange;

void handleSelectionChange(Object sender){
    //handle event
}
Soni Ali
fuente
He intentado estas respuestas, pero nadie fue útil. Una vez que el componente Spinner no admite eventos de clic de elemento. Documentación de Spinner

Respuestas:

812

Algunas de las respuestas anteriores no son correctas. Funcionan para otros widgets y vistas, pero la documentación del widget Spinner establece claramente:

Una ruleta no admite eventos de clic de elemento. Llamar a este método generará una excepción.

Mejor use OnItemSelectedListener () en su lugar:

spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
        // your code here
    }

    @Override
    public void onNothingSelected(AdapterView<?> parentView) {
        // your code here
    }

});

Esto funciona para mi.

Tenga en cuenta que el método onItemSelected también se invoca cuando se construye la vista, por lo que puede considerar ponerlo dentro de la onCreate()llamada al método.

znq
fuente
47
El problema con esto es que el método onItemSelected también se invoca cuando se construye la vista. Entonces, el código que está escrito allí también se ejecuta al inicio. ¿Hay alguna forma de ejecutar el código que contiene solo si el usuario invoca una selección de elemento real?
Kennethvr
39
en realidad, ese problema se puede resolver colocando setOnItemSelectedListener en el método de anulación OnStart y no en el método onCreate. estúpido ...
Kennethvr
16
Puse el oyente en el método onStart, pero se llama antes de que el usuario pueda ver algo, al igual que onCreate, por lo que, en mi caso, un botón "continuar" que debe ser invisible hasta que el usuario seleccione algo, el botón se hace visible en la pantalla inicial. ¿Estás diciendo que tu experiencia es diferente? Si es así, ¿qué está haciendo de manera diferente en el método onStart que me falta?
Yevgeny Simkin
77
Utilice otro campo dentro de su escucha anónima para grabar la primera selección y dígale a onItemSelected que no haga nada a menos que se haya encontrado una selección. Solo un pensamiento.
Sam Svenbjorgchristiensensen
44
Pero, ¿qué sucede si el usuario selecciona el elemento "predeterminado", el que está arriba? Entonces onItemSelected(...)no es golpeado. (Lo sé porque me acabo de enterar por las malas)
Andrew Wyld
55
Spinner spnLocale = (Spinner)findViewById(R.id.spnLocale);

spnLocale.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { 
        // Your code here
    } 

    public void onNothingSelected(AdapterView<?> adapterView) {
        return;
    } 
}); 

Nota: recuerda una cosa.

El OnItemSelectedListenerevento Spinner se ejecutará dos veces:

  1. Spinner initialization
  2. Usuario seleccionado manualmente

Intenta diferenciar esos dos usando la variable flag.

Santhosh
fuente
3
¡El mío se llama dos veces también! No puedo entender cómo diferenciar entre los dos?
MAC
18
Simplemente configure un booleano global como Boolean initialDisplay = true; Y luego, en su onSelect, vea si es cierto y, en caso afirmativo, no haga lo que fuera a hacer en select, sino que establezca el indicador en falso, para la próxima vez que se llame (cuando el usuario realmente seleccione).
Yevgeny Simkin
La mejor explicación sobre la ejecución de OnclickListener.
Pankaj Kumar
66
Personalmente, me horroriza que algo tan simple, un widget de interfaz de usuario tan fundamental, sea tan sangrientamente difícil de implementar ... en serio, lo difícil que sería construir una propiedad de 'elemento de visualización predeterminado' y construir la propiedad de bandera booleana en el objeto clase en sí? No soy fanático de Objective C, pero diré que la implementación de widgets de iOS tarda aproximadamente 1/10 del tiempo que lo hace en Android.
Bennett Von Bennett
44
Yo tambien estoy de acuerdo. El Spinner es un widget jodido. Es muy difícil saber cuándo el popup o drop está abierto o cerrado. ¿Habría sido tan difícil agregar un evento para esto? La solución anterior casi le puede decir cuando la lista está abierta o cerrada pero tiene tres problemas: (1) no hay evento para seleccionar el elemento ya seleccionado (y la lista se cierra) y (2) no hay evento para cancelar (toque fuera de la lista para cerrarlo) y (3) onNothingSelected nunca parece dispararme.
Batdude
19

Puede implementar la AdapterView.OnItemSelectedListenerclase en su actividad.

Y luego use la siguiente línea dentro de onCreate()

Spinner spin = (Spinner) findViewById(R.id.spinner);
spin.setOnItemSelectedListener(this);

Luego anule estos dos métodos:

public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
    selection.setText(items[position]);
}

public void onNothingSelected(AdapterView<?> parent) {
    selection.setText("");
}
Dhasneem
fuente
16

https://stackoverflow.com/q/1714426/811625

Puede evitar que se llame a OnItemSelectedListener () con una simple verificación: almacene el índice de selección actual en una variable entera y verifique dentro de onItemSelected (..) antes de hacer nada.

P.ej:

Spinner spnLocale;

spnLocale = (Spinner)findViewById(R.id.spnLocale);

int iCurrentSelection = spnLocale.getSelectedItemPosition();

spnLocale.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { 
    if (iCurrentSelection != i){
            // Your code here
    }
    iCurrentSelection = i;
    } 

    public void onNothingSelected(AdapterView<?> adapterView) {
        return;
    } 
}); 

Por supuesto, ¡ iCurrentSelectiondebe estar en el alcance del objeto para que esto funcione!

Sampath
fuente
1
No puede usar una variable no final dentro de una clase interna anónima. Si la iCurrentSelectionvariable se declara dentro de esta clase anónima, funcionará bien. Puede inicializarlo a -1 para que el código se ejecute en la primera llamada.
dahvyd
2
@dahvyd era correcto si usa esto, el int debe ser final. En cualquier caso, funciona muy bien. Estaba deshabilitando un campo EditText si la posición 0 no estaba seleccionada y si cambiaba, lo volví a habilitar. Gracias por esto.
natur3
8

Encuentre su nombre de hilandero y busque la identificación, luego implemente este método.

spinnername.setOnItemSelectedListener(new OnItemSelectedListener() {

    @Override
    public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
        // your code here
    }

    @Override
    public void onNothingSelected(AdapterView<?> parentView) {
        // your code here
    }
});
droidster.me
fuente
8

No importa si configurará OnItemSelectedListener en onCreate o onStart; todavía se llamará durante la creación o el inicio de la Actividad (respectivamente).
Entonces podemos configurarlo en onCreate (y NO en onStart!).
Simplemente agregue una bandera para descubrir la primera inicialización:

private Spinner mSpinner;
private boolean mSpinnerInitialized;

luego en onCreate (o onCreateView) solo:

mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                if (!mSpinnerInitialized) {
                    mSpinnerInitialized = true;
                    return;
                }

                // do stuff
            }

            public void onNothingSelected(AdapterView<?> adapterView) {
                return;
            }
        });
Leo Droidcoder
fuente
1
Gracias por usar esta bandera.
Javan R.
7

Los documentos para el widget spinner dice

Una ruleta no admite eventos de clic de elemento.

Debe usar setOnItemSelectedListenerpara manejar su problema.

johndotnet
fuente
6
spinner1.setOnItemSelectedListener(
    new AdapterView.OnItemSelectedListener() {
        //add some code here
    }
);
Chiwai Chan
fuente
1
Esto no soluciona el problema de que se llame a esta devolución de llamada cuando se inicia por primera vez la ruleta (provocando así una respuesta que no tiene nada que ver con un elemento que se está seleccionando realmente).
Yevgeny Simkin
4

tomar una variable global para la selección actual de spinner:

int currentItem = 0;

spinner_counter = (Spinner)findViewById(R.id.spinner_counter);
String[] value={"20","40","60","80","100","All"};
aa=new ArrayAdapter<String>(this,R.layout.spinner_item_profile,value);
aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_counter.setAdapter(aa);

spinner_counter.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if(currentItem == position){
                return; //do nothing
            }
            else
            {
                 TextView spinner_item_text = (TextView) view;
                 //write your code here
            }
            currentItem = position;
        }

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

        }
    });

//R.layout.spinner_item_profile
<?xml version="1.0" encoding="utf-8"?>

<TextView  android:id="@+id/spinner_item_text"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" 
android:layout_height="wrap_content"
android:background="@drawable/border_close_profile"
android:gravity="start"  
android:textColor="@color/black"         
android:paddingLeft="5dip"
android:paddingStart="5dip"
android:paddingTop="12dip"
android:paddingBottom="12dip"
/>

//drawable/border_close_profile
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item>
   <shape android:shape="rectangle">
    <solid android:color="#e2e3d7" />
   </shape>
 </item>
<item android:left="1dp"
android:right="1dp"
android:top="1dp"
android:bottom="1dp">
<shape android:shape="rectangle">
    <solid android:color="@color/white_text" />
</shape>
</item>
</layer-list>
indrajeet
fuente
4

Si quieres un verdadero onChangedListener (). Almacene el valor inicial en el controlador y verifique si ha cambiado. Es simple y no requiere una variable global. Funciona si tienes más de una ruleta en la página.

String initialValue = // get from Database or your object
mySpinner.setOnItemSelectedListener(new SpinnerSelectedListener(initialValue));

...

protected class SpinnerSelectedListener implements AdapterView.OnItemSelectedListener {

        private SpinnerSelectedListener() {
            super();
        }

        public SpinnerSelectedListener(String initialValue) {
            this();
            this.initialValue = initialValue;
        }

        private String initialValue;

        // getter and setter removed.  

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            final String newValue = (String) spinHeight.getItemAtPosition(position);
            if (newValue.equals(initialValue) == false) {
               // Add your code here.  The spinner has changed value. 

               // Maybe useful.   
               // initialValue = newValue;
            }

        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
               // Maybe useful.   
               // initialValue = null; 
        }
    }

Los objetos son tus amigos, úsalos.

fishjd
fuente
3
spinner.setOnItemSelectedListener(
            new AdapterView.OnItemSelectedListener() {

                @Override
                public void onItemSelected(AdapterView<?> arg0, View arg1,
                        int arg2, long arg3) {

                    // TODO Auto-generated method stub
                }

                @Override
                public void onNothingSelected(AdapterView<?> arg0) {
                    // TODO Auto-generated method stub

                }
                //add some code here
            }
        );
kaub0st3r
fuente
1

Esto funcionará para inicializar la ruleta y findviewbyid y usar esto funcionará

    Spinner schemeStatusSpinner;

  schemeStatusSpinner = (Spinner) dialog.findViewById(R.id.spinner);

schemeStatusSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
            // your code here
            if(schemeStatusSpinner.getSelectedItemId()==4){
                reasonll.setVisibility(View.VISIBLE);
            }
            else {
                reasonll.setVisibility(View.GONE);
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> parentView) {
            // your code here
        }

    });
sanjay
fuente
1

La mejor forma de lo que creo que sería tener una flagitemselected = 0;en onCreate(). Y el elemento seleccionado de la subasta caso de que la bandera es decir flagitemselected++; y luego verifica

if(flagitemselected!=1)
{
// do your work here
}

Esto ayudará, supongo.

Pinakin
fuente
0

Un truco que encontré fue poner sus setOnItemSelectedListeners en onWindowFocusChanged en lugar de onCreate. Todavía no he encontrado ningún efecto secundario negativo al hacerlo de esta manera. Básicamente, configure los oyentes después de que se dibuje la ventana. No estoy seguro de con qué frecuencia se ejecuta onWindowFocusChanged, pero es bastante fácil crearse una variable de bloqueo si la encuentra ejecutándose con demasiada frecuencia.

Creo que Android podría estar usando un sistema de procesamiento basado en mensajes, y si lo pones todo en onCreate, es posible que te encuentres en situaciones en las que el spinner se llena después de que se dibuja. Por lo tanto, su oyente se disparará después de establecer la ubicación del elemento. Esta es una suposición educada, por supuesto, pero no dude en corregirme al respecto.

Joe Plante
fuente
0

De forma predeterminada, obtendrá el primer elemento de la matriz giratoria a través de

value = spinner.getSelectedItem().toString();

cada vez que seleccionó el valor en la ruleta, esto le dará el valor seleccionado

si desea la posición del elemento seleccionado, hágalo así

pos = spinner.getSelectedItemPosition();

las dos respuestas anteriores son para sin aplicar oyente

Adam Noor
fuente