¿Cómo puedo obtener un evento en Android Spinner cuando se selecciona de nuevo el elemento seleccionado actualmente?

He escrito un setOnItemSelectedListener para que spinner responda cuando se cambie el ítem giratorio. Mi requisito es que cuando vuelva a hacer clic en el elemento seleccionado, se muestre una tostada. ¿Cómo obtener este evento? Cuando se vuelve a hacer clic en el elemento seleccionado actualmente, el girador no responde. `

StorageSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){ @Override public void onItemSelected(AdapterView adapter, View v, int i, long lng) { Toast.makeText(getApplicationContext(), (CharSequence) StorageSpinner.getSelectedItem(), Toast.LENGTH_SHORT).show(); } @Override public void onNothingSelected(AdapterView arg0) { Toast.makeText(getApplicationContext(), "Nothing selected", Toast.LENGTH_SHORT).show(); } }); 

Cuando vuelve a hacer clic en el elemento seleccionado actualmente, no puede activar ningún evento. Entonces no puedes capturar setOnItemSelectedListener para que spinner responda.

Pasé unas buenas horas tratando de obtener algo para resolver este problema. Terminé con lo siguiente. No estoy seguro de si funciona en todos los casos, pero parece funcionar para mí. Es solo una extensión de la clase Spinner que verifica la selección y llama al oyente si la selección se establece en el mismo valor.

 import android.content.Context; import android.util.AttributeSet; import android.widget.Spinner; /** Spinner extension that calls onItemSelected even when the selection is the same as its previous value */ public class NDSpinner extends Spinner { public NDSpinner(Context context) { super(context); } public NDSpinner(Context context, AttributeSet attrs) { super(context, attrs); } public NDSpinner(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public void setSelection(int position, boolean animate) { boolean sameSelected = position == getSelectedItemPosition(); super.setSelection(position, animate); if (sameSelected) { // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId()); } } @Override public void setSelection(int position) { boolean sameSelected = position == getSelectedItemPosition(); super.setSelection(position); if (sameSelected) { // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId()); } } } 

prueba esto

 public class MySpinner extends Spinner{ OnItemSelectedListener listener; public MySpinner(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void setSelection(int position) { super.setSelection(position); if (position == getSelectedItemPosition()) { listener.onItemSelected(null, null, position, 0); } } public void setOnItemSelectedListener(OnItemSelectedListener listener) { this.listener = listener; } } 

Este spinner siempre te dirá que la selección ha cambiado:

 package com.mitosoft.ui.widgets; import java.lang.reflect.Method; import android.content.Context; import android.content.DialogInterface; import android.util.AttributeSet; import android.util.Log; import android.widget.AdapterView; import android.widget.Spinner; //com.mitosoft.ui.widgets.NoDefaultSpinner public class NoDefaultSpinner extends Spinner { private int lastSelected = 0; private static Method s_pSelectionChangedMethod = null; static { try { Class noparams[] = {}; Class targetClass = AdapterView.class; s_pSelectionChangedMethod = targetClass.getDeclaredMethod("selectionChanged", noparams); if (s_pSelectionChangedMethod != null) { s_pSelectionChangedMethod.setAccessible(true); } } catch( Exception e ) { Log.e("Custom spinner, reflection bug:", e.getMessage()); throw new RuntimeException(e); } } public NoDefaultSpinner(Context context) { super(context); } public NoDefaultSpinner(Context context, AttributeSet attrs) { super(context, attrs); } public NoDefaultSpinner(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public void testReflectionForSelectionChanged() { try { Class noparams[] = {}; s_pSelectionChangedMethod.invoke(this, noparams); } catch (Exception e) { Log.e("Custom spinner, reflection bug: ", e.getMessage()); e.printStackTrace(); } } @Override public void onClick(DialogInterface dialog, int which) { super.onClick(dialog, which); if(lastSelected == which) testReflectionForSelectionChanged(); lastSelected = which; } } 

para las plataformas más nuevas intente agregar esto a la solución de Dimitar. Creo que funciona 🙂

(debe sobrescribir OnLayout y eliminar el método OnClick)

  @Override public void onClick(DialogInterface dialog, int which) { super.onClick(dialog, which); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if(this.lastSelected == this.getSelectedItemPosition()) testReflectionForSelectionChanged(); if(!changed) lastSelected = this.getSelectedItemPosition(); super.onLayout(changed, l, t, r, b); } 

Pensé que dejaría una respuesta actualizada para aquellos que trabajan en las versiones más nuevas de Android.

Recopilé una función de las respuestas anteriores que funcionará para al menos 4.1.2 y 4.3 (los dispositivos que probé). Esta función no utiliza el reflection, sino que rastrea el último índice seleccionado, por lo que debe ser seguro incluso si el SDK cambia la forma en que las clases se extienden entre sí.

 import android.content.Context; import android.util.AttributeSet; import android.widget.Spinner; public class SelectAgainSpinner extends Spinner { private int lastSelected = 0; public SelectAgainSpinner(Context context) { super(context); } public SelectAgainSpinner(Context context, AttributeSet attrs) { super(context, attrs); } public SelectAgainSpinner(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if(this.lastSelected == this.getSelectedItemPosition() && getOnItemSelectedListener() != null) getOnItemSelectedListener().onItemSelected(this, getSelectedView(), this.getSelectedItemPosition(), getSelectedItemId()); if(!changed) lastSelected = this.getSelectedItemPosition(); super.onLayout(changed, l, t, r, b); } } 

Lo que encontré es que OnItemSelectedListener no se llamará si el mismo elemento se selecciona de nuevo en un spinner. Cuando hago clic en spinner y de nuevo selecciono el mismo valor, no se llama al método OnItemSelectedListener. Las personas no esperan que ocurra algo si hacen clic en una selección que ya está activa según el diseño de la interfaz de usuario.

@Dimitar. WOW, shiny trabajo. Gracias por eso. No puedo promocionar tu solución (no hay suficientes puntos) pero la clase NoDefaultSpinner FUNCIONA. Solo una cosa era un problema: como llama a super.onClick y luego a testReflectionForSelectionChanged () dentro de “OnClick”, obtendrá el controlador onItemSelected para el spinner que se llama dos veces si la selección realmente cambia (mientras que la funcionalidad es correcta si es la misma el artículo es re-seleccionado). Lo solucioné pirateando. Agregué una anulación onTouchEvent que registró qué elemento se tocó, luego verifiqué si esto había cambiado en “onClick”:

 private Object ob=null; //class level variable @Override public boolean onTouchEvent(MotionEvent m) { if (m.getAction()==MotionEvent.ACTION_DOWN) { ob=this.getSelectedItem(); } return super.onTouchEvent(m); } @Override public void onClick(DialogInterface dialog, int which) { super.onClick(dialog, which); if (this.getSelectedItem().equals(ob)) testReflectionForSelectionChanged(); } 

Hola y gracias @Dimitar por una respuesta creativa al problema. Lo probé y funciona bien en versiones anteriores de Android como 2.x, pero desafortunadamente no funciona en la versión 3.0 y posterior (intenté con 3.2 y 4.0.3). Por alguna razón, nunca se llama al método onClick en las plataformas más nuevas. Alguien ha escrito un informe de error para esto aquí: http://code.google.com/p/android/issues/detail?id=16245

No funcionar en plataformas más nuevas significa que necesitaba una solución diferente. En mi aplicación fue suficiente para simular un spinner no seleccionado con una entrada oculta “ficticia” al inicio. Luego, cada elemento en el que se haga clic dará lugar a una callback si el elemento “oculto” está configurado como la selección. Una desventaja para algunos puede ser que nada aparecerá seleccionado, pero que podría ser arreglado utilizando trucos de anulación de clase Spinner.

Consulte Cómo ocultar un elemento en un Spinner de Android

El comportamiento de Spinner no se espera para nuestros requisitos. Mi solución no es trabajar con Spinners, hacerlo de una manera similar, con un ListView dentro de un BaseFragment para investigar la funcionalidad que se espera.

Los beneficios son:

  1. No más dolores de cabeza extendiendo los valores predeterminados de Spinner.
  2. Fácil implementación y personalización.
  3. Compatibilidad total con todas las API de Android.
  4. Sin rostro frente a la primera llamada OnItemSelectedListener.onItemSelected.

La idea principal es hacer algo como esto:

El diseño de BaseFragment podría ser similar a:

    

El código se ve así:

 public class SpinnerListFragment extends android.support.v4.app.DialogFragment { static SpinnerListFragment newInstance(List items) { SpinnerListFragment spinnerListFragment = new SpinnerListFragment(); Bundle args = new Bundle(); args.putCharSequenceArrayList("items", (ArrayList) items); spinnerListFragment.setArguments(args); return spinnerListFragment; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { Dialog dialog = new Dialog(getActivity(), R.style.dialog); final View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_spinner_list, null); dialog.getWindow().setContentView(view); dialog.setCanceledOnTouchOutside(true); // CUSTOMIZATION... final List items = (ArrayList) getArguments().getCharSequenceArrayList("items"); final ListView spinnerList = (ListView) view.findViewById(R.id.fragment_spinnerList); ArrayAdapter arrayAdapter = new ArrayAdapter( getActivity(), R.layout.search_spinner_list_item, items); spinnerList.setAdapter(arrayAdapter); spinnerList.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { // DO SOMETHING... SpinnerListFragment.this.dismiss(); } }); return dialog; } } 

Mi solución está basada en MySpinner por benoffi7. Corrige los nulos pasados ​​en la misma selección de elementos al guardar el último elemento primario y la vista seleccionados.

 public class MySpinner extends Spinner { private OnItemSelectedListener listener; private AdapterView lastParent; private View lastView; private long lastId; public MySpinner(Context context, AttributeSet attrs) { super(context, attrs); initInternalListener(); } public MySpinner(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initInternalListener(); } private void initInternalListener() { super.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { lastParent = parent; lastView = view; lastId = id; if (listener != null) { listener.onItemSelected(parent, view, position, id); } } @Override public void onNothingSelected(AdapterView parent) { //lastParent = parent; // do we need it? if (listener != null) { listener.onNothingSelected(parent); } } }); } @Override public void setSelection(int position) { if (position == getSelectedItemPosition() && listener != null) { listener.onItemSelected(lastParent, lastView, position, lastId); } else { super.setSelection(position); } } @Override public void setOnItemSelectedListener(OnItemSelectedListener listener) { this.listener = listener; } } 
 class MySpinner extends Spinner { public MySpinner(Context context) { super(context); // TODO Auto-generated constructor stub } public MySpinner(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void setSelection(int position, boolean animate) { ignoreOldSelectionByReflection(); super.setSelection(position, animate); } private void ignoreOldSelectionByReflection() { try { Class c = this.getClass().getSuperclass().getSuperclass().getSuperclass(); Field reqField = c.getDeclaredField("mOldSelectedPosition"); reqField.setAccessible(true); reqField.setInt(this, -1); } catch (Exception e) { Log.d("Exception Private", "ex", e); // TODO: handle exception } } @Override public void setSelection(int position) { ignoreOldSelectionByReflection(); super.setSelection(position); } } 

Esta no es una solución completa, pero funciona si solo quieres llamar a esto cuando estés regresando a tu fragmento / actividad desde cualquier lugar.

Teniendo en cuenta que mSpinner es su vista de Spinner, lo llamamos oyente así:

 @Override public void onResume() { if ( mSpinner.getCount() > 0 ) { mSpinner.getOnItemSelectedListener() .onItemSelected( mSpinner, null, mSpinner.getSelectedItemPosition(), 0 ); } super.onResume(); } 

Esto tiene una solución fácil porque es posible establecer el “elemento seleccionado” programáticamente según “onTouch”, así:

 spinnerobject.setOnTouchListener(new AdapterView.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { final int MAKE_A_SELECTION = 1; //whatever index that is the normal starting point of the spinner. spinnerObject.setSelection(MAKE_A_SELECTION); return false; } }); 

Existe una pequeña penalización en el sentido de que (1) el texto del rotador cambiará a la configuración predeterminada justo antes de que se muestren las filas del rotador, y (2), este elemento predeterminado será parte de la lista. Tal vez alguien puede agregar cómo desactivar un elemento en particular para un spinner?

En general, dado que una selección de spinner puede ejecutar un evento repetible (como iniciar una búsqueda), la falta de posibilidad de volver a seleccionar un ítem en un spinner es realmente una característica faltante en la clase Spinner, un error que los desarrolladores de Android deberían corregir lo antes posible. .

Hola, esto funcionó para mí:

 ArrayAdapter adaptador1 = new ArrayAdapter( Ed_Central.this, android.R.layout.simple_spinner_item, datos1 ); lista1.setAdapter( adaptador1 ); lista1.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected( AdapterView parent, View view, int position, long id ) { lista1.setSelection( 0 ); switch ( position ) { case 1: Toast.makeText( getApplicationContext(), "msg1", Toast.LENGTH_SHORT ).show(); break; case 2: Toast.makeText( getApplicationContext(), "msg2", Toast.LENGTH_SHORT ).show(); break; case 3: Toast.makeText( getApplicationContext(), "msg3", Toast.LENGTH_SHORT ).show(); break; default: break; } } 

Siempre el adaptador va a estar en la posición “0”, y puede mostrar sus tostadas.

si realmente desea hacer esta tarea en su XML cuando su pantalla giratoria agregue un texto de edición y establezca el atributo visibilidad perdida; y crea un adaptador de vestuario para spinner y en el adaptador de disfraz establecido en view.onclicklisner y cuando clickevent dispara EditText.setText (“0”); y en la actividad establece el texto de edición textWatcher Event y en el bloque de eventos agrega el código del Bloque de eventos onSppinerItem; Su problema resuelto

 package customclasses; /** * Created by Deepak on 7/1/2015. */ import android.content.Context; import android.util.AttributeSet; import android.widget.Spinner; /** * Spinner extension that calls onItemSelected even when the selection is the same as its previous value */ public class NDSpinner extends Spinner { public boolean isDropDownMenuShown=false; public NDSpinner(Context context) { super(context); } public NDSpinner(Context context, AttributeSet attrs) { super(context, attrs); } public NDSpinner(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public void setSelection(int position, boolean animate) { boolean sameSelected = position == getSelectedItemPosition(); super.setSelection(position, animate); if (sameSelected) { // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId()); } } @Override public boolean performClick() { this.isDropDownMenuShown = true; //Flag to indicate the spinner menu is shown return super.performClick(); } public boolean isDropDownMenuShown(){ return isDropDownMenuShown; } public void setDropDownMenuShown(boolean isDropDownMenuShown){ this.isDropDownMenuShown=isDropDownMenuShown; } @Override public void setSelection(int position) { boolean sameSelected = position == getSelectedItemPosition(); super.setSelection(position); if (sameSelected) { // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId()); } } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); } } 

Solo prueba con esto.

 @Override public void onItemSelected(AdapterView adapter, View v, int i, long lng) { if(v.hasFocus() { Toast.makeText(getApplicationContext(), (CharSequence) StorageSpinner.getSelectedItem(), Toast.LENGTH_SHORT).show(); } } 

Espero que pueda funcionar