Cómo cambiar el valor de NumberPicker con animación?

He creado una aplicación para Android, en la que hay un NumberPicker. Y necesito cambiar el valor de este NumberPicker pero con una animación lisa como cuando usted lo toca y cambia su valor.

Por ejemplo, supongamos que el valor actual es 1 y va a ser 5, quiero que el NumberPicker gire de 1 a 2 y luego a 3 y así sucesivamente. Pero quiero que gire no sólo al instante cambiar los valores!

Si utilizo el código siguiente:

numberPicker.setValue(5); 

Su valor cambiará instantáneamente a 5, pero quiero que ruede de 1 a 5 como cuando lo toque manualmente y lo haga girar.

Lo resolví vía refelction

  /** * using reflection to change the value because * changeValueByOne is a private function and setValue * doesn't call the onValueChange listener. * * @param higherPicker * the higher picker * @param increment * the increment */ private void changeValueByOne(final NumberPicker higherPicker, final boolean increment) { Method method; try { // refelction call for // higherPicker.changeValueByOne(true); method = higherPicker.getClass().getDeclaredMethod("changeValueByOne", boolean.class); method.setAccessible(true); method.invoke(higherPicker, increment); } catch (final NoSuchMethodException e) { e.printStackTrace(); } catch (final IllegalArgumentException e) { e.printStackTrace(); } catch (final IllegalAccessException e) { e.printStackTrace(); } catch (final InvocationTargetException e) { e.printStackTrace(); } } 

Funciona perfecto. No sé por qué este método es privado

No creo que esto esté apoyado nativamente. Pensé en una forma "desordenada" de hacerlo manualmente:

Puede utilizar la función scrollBy (int x, int y) del NumberPicker llamada iterativamente para realizar el efecto de la animación.

Algunas cosas a tener en cuenta:

  • ScrollBy (x, y) funciona con píxeles. Como Android tiene todas esas diferentes densidades de pantalla, lo que debes hacer es adivinar primero (lo haría por prueba y error) la distancia 'dp' que corresponde al desplazamiento a un valor consecutivo, y convertirlo a píxeles para Úsalo
  • El primer parámetro de scrollBy (x, y) debe tomar un valor de 0, en caso de que no sea obvio

No he hecho animaciones yo mismo en Android, pero hay una API muy buena desde Honeycomb que probablemente hace que sea fácil de lograr esto.

Lo siento, pero este es el más fácil que podía pensar!

EDIT: Para convertir de 'dp' a pixeles:

 private float pxFromDp(float dp) { return dp * this.getContext().getResources().getDisplayMetrics().density; } 

Lo que tendrás que hacer es probar la llamada a scrollBy (0, pxFromDp (dp)) con diferentes valores 'dp', hasta que obtengas el exacto que mueve el NumberPicker hasta un número. Una vez que obtenga ese valor, puede crear su método de animación que al mover hacia arriba los números X desplazará X veces esta distancia dp.

Por favor, pregunte de nuevo si no lo entiende completamente 🙂

Gracias @passsy. Inspirado su respuesta: Esta solución admite múltiples pasos de incremento / decremento . Además, se puede ejecutar con un retardo de inicio y para varios númeroPickers (sin codificación adicional) .

 class IncreaseValue { private int counter = 0; private final NumberPicker picker; private final int incrementValue; private final boolean increment; private final Handler handler = new Handler(); private final Runnable fire = new Runnable() { @Override public void run() { fire(); } }; /*public*/ IncreaseValue(final NumberPicker picker, final int incrementValue) { this.picker = picker; if (incrementValue > 0) { increment = true; this.incrementValue = incrementValue; } else { increment = false; this.incrementValue = -incrementValue; } } /*public*/ void run(final int startDelay) { handler.postDelayed(fire, startDelay); // This will execute the runnable passed to it (fire) // after [startDelay in milliseconds], ASYNCHRONOUSLY. } private void fire() { ++counter; if (counter > incrementValue) return; try { // refelction call for // picker.changeValueByOne(true); final Method method = picker.getClass().getDeclaredMethod("changeValueByOne", boolean.class); method.setAccessible(true); method.invoke(picker, increment); } catch (final NoSuchMethodException | InvocationTargetException | IllegalAccessException | IllegalArgumentException e) { Log.d(TAG, "...", e); } handler.postDelayed(fire, 120); // This will execute the runnable passed to it (fire) // after 120 milliseconds, ASYNCHRONOUSLY. Customize this value if necessary. } } 

El uso:

 // Suppose picker1 as a NumberPicker IncreaseValue increasePicker1 = new IncreaseValue(picker1, 10); // So picker1 will be increased 10 steps. increasePicker1.run(0); // Increase immediately. If you want to run it from onCreate(), onStart() or ... of your activity, you will probably need to pass a positive value to it (eg 100 milliseconds). 

Hay método privado dentro de NumberPicker, que es

 changeCurrentByOne(boolean increment) 

Puedes hacerlo público y usarlo. Puede ver este método en acción al presionar la flecha ARRIBA o ABAJO de NumberPicker. Probablemente no es lo que estás buscando, ya que este método no da mucho control de animación, pero es definitivamente mejor que setValue . Sin ninguna animación setValue parece terrible para el usuario.

  • Cómo restablecer los datos de NumberPicker
  • Numberpicker lanza ArrayIndexOutOfBoundsException al desplazarse por los valores
  • Modificación o cambio de valores mínimos, máximos y mostrados para NumberPicker
  • Android NumberPicker - Números negativos
  • Cambiar la velocidad de lanzamiento de Android Numberpicker dentro de un Alertdialog
  • ¿Cómo saltar un número de selector de números?
  • NPE en ChangeCurrentByOneFromLongPressCommand (en dispositivos Samsung con Android 4.3)
  • Cambio del color del divisor de NumberPicker
  • Seleccionador de números de Android obtiene valor para textview
  • Cambiar el color de texto de NumberPicker
  • Android numberpicker para números de coma flotante
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.