Cómo deshabilitar onItemSelectedListener que se invocará al configurar el elemento seleccionado por código
Sólo se pregunta cómo manejar el problema siguiente: un resultado se calcula en función de dos elementos seleccionados de hilanderos. Para manejar las cosas de la interfaz de usuario, es decir, un usuario escoge un elemento nuevo en una de las hiladoras, instalo un oyente utilizando setOnItemSelectedListener
para la hiladora en mi método onCreate()
de la actividad.
Ahora: eso funciona, por supuesto, bien. El trabajo del oyente es activar un nuevo cálculo del resultado.
- Tamaño del texto de un spinner
- Cómo ocultar un elemento en un Spinner de Android
- Creación de un setError () para el Spinner
- Crear un hilandero por programación android
- ¿Cómo puedo cambiar o disminuir el tamaño de la ruleta de Android?
El problema: porque intercepto onPause()
onResume()
para guardar / restaurar el último estado, tengo un método que establece el elemento seleccionado por estos dos hilanderos de forma programática como aquí:
startSpinner.setSelection(pStart); destSpinner.setSelection(pDest);
¡Estas dos llamadas invocan a los oyentes, también! Mi método de cálculo para el resultado más la notificación de un nuevo conjunto de resultados se invoca dos veces aquí!
Una aproximación directa estúpida para esto sería tener una variable booleana que inhabilite lo que el oyente hace dentro, fijándola antes de fijar los artículos seleccionados y de reajustarlo después. Bueno. ¿Pero hay un método mejor?
¡No quiero que los oyentes sean llamados por acciones de código, solo por las acciones del usuario! Unesdoc.unesco.org
¿Cómo lo haces? ¡Gracias!
- ¿Cómo hago para que el estado "deshabilitado" de un Spinner esté deshabilitado?
- Spinner Tamaño Pequeño
- Cómo configurar el texto del hilandero actual sin cambiar los elementos de la lista de selección asociada
- Tamaño del texto del hilandero Android
- Uso correcto de un Spinner, siguiendo las directrices de diseño del material
- Android - Spinner + setOnClickListener
- Tema predeterminado de Spinner a EditarTexto android
- Android - Eliminar Spinner Dropdown Arrow
Tengo una solución más fácil, y creo que mejor. Dado que tuve que actualizar los hiladores incluso después de la inicialización, este es un enfoque más genérico. Por favor, consulte la respuesta aceptada:
Llamadas no deseadas onItemSelected
Una solución más limpia, en mi opinión, para diferenciar entre los cambios programáticos y iniciados por el usuario es la siguiente:
Crear su oyente para el hilandero como un OnTouchListener y OnItemSelectedListener
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; } } }
Agregue el oyente al registro de hilandero para ambos tipos de evento
SpinnerInteractionListener listener = new SpinnerInteractionListener(); mSpinnerView.setOnTouchListener(listener); mSpinnerView.setOnItemSelectedListener(listener);
De esta manera, cualquier llamada inesperada a su método de controlador debido a la inicialización o reinicialización se ignorará.
Bueno, lo tengo funcionando de la manera que quiero ahora.
Lo que hay que entender aquí (y no lo hice cuando estaba escribiendo esa pregunta …) es que todo en Android se ejecuta en un hilo – el hilo de la interfaz de usuario.
Lo que significa: a pesar de que establece los valores de Spinner aquí y allá: sólo se actualizan (visualmente) y sus oyentes sólo se llaman después de todos los métodos que están actualmente en (como onCreate
, onResume
o lo que sea) están terminados.
Esto permite lo siguiente:
- Mantener las posiciones seleccionadas en las variables de campo. (Como
currentPos1
,currentPos2
) - Los oyentes
onItemSelectedListener()
llaman a un método comorefreshMyResult()
o lo que sea. - Al establecer las posiciones de forma programática, establecer los hilanderos y llamar a su propio método de actualización manualmente después de eso.
El método refreshMyResult()
tiene este aspecto:
int newPos1 = mySpinner1.getSelectedItemPosition(); int newPos2 = mySpinner2.getSelectedItemPosition(); // only do something if update is not done yet if (newPos1 != currentPos1 || newPos2 != currentPos2) { currentPos1 = newPos1; currentPos2 = newPos2; // do whatever has to be done to update things! }
Porque los oyentes serán llamados más tarde – y para entonces, la posición recordada en currentPos ya está actualizada – no pasará nada y ninguna actualización innecesaria de cualquier otra cosa tendrá lugar. Cuando un usuario selecciona un nuevo valor en uno de los hiladores, bien – la actualización se realizará en consecuencia!
¡Eso es! Todos los derechos reservados
Ahh – una cosa más: la respuesta a mi pregunta es: No. Los oyentes no pueden ser inhabilitados (fácilmente) y serán llamados cada vez que cambie un valor.
Es muy fácil que puedas llamar al método Spinner.setSelection(int position, boolean animate)
con false
para que los oyentes no reaccionen en el cambio.
Spinner.setSelection (int position, boolean animate) activa el oyente en 4.3
He creado una biblioteca que ayuda para todos, que no hay necesidad de llamar al elemento onClick acción en Spinner Por ejemplo:
spinner.setSelection(withAction,position);
Donde withAction es un indicador booleano, que se utiliza para la acción de llamada o no
Enlace en Github: https://github.com/scijoker/spinner2
Agregue OnItemSelectedListener
para cada hilandero después de haber establecido cualquier valor anterior en onResume
.
Cuando se utiliza Spinner.setSelection (posición), siempre activa setOnItemSelectedListener ()
Para evitar disparar el código dos veces utilizo esta solución:
private mIsSpinnerFirstCall=true; ... Spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { //If a new value is selected (avoid activating on setSelection()) if(!mIsSpinnerFirstCall) { // Your code goes gere } mIsSpinnerFirstCall = false; } public void onNothingSelected(AdapterView<?> arg0) { } });
Esta solución es válida cuando estés seguro de que Spinner.setSelection (position) us us. Además, es importante establecer mIsSpinnerFirstCall = true cada vez antes de usar Spinner.setSelection (posición)