如何更改NumberPicker的值与animation?

我为Android创build了一个应用程序,其中有一个NumberPicker。 而且我需要改变这个NumberPicker的值,但是像一个平滑的animation一样,当你触摸它并改变它的值。

例如,假设当前值为1,它将会是5,我希望NumberPicker从1旋转到2,然后旋转到3,依此类推。 但是我希望它不仅能立即改变价值!

如果我使用下面的代码:

numberPicker.setValue(5); 

它的值会立即变为5,但是我希望它从1到5滚动,就像手动触摸它并旋转一样。

我通过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(); } } 

作品完美。 我不知道为什么这个方法是私人的

我不相信这是本地支持。 我想到了一个手动的“混乱”的方式:

您可以使用迭代调用的NumberPicker的scrollBy(int x,int y)函数来产生animation效果。

有些事情要考虑到:

  • scrollBy(x,y)适用于像素。 由于Android已经有了所有不同的屏幕密度,你应该做的是首先猜测(我会做试验和错误)与滚动到连续值对应的“dp”距离,并将其转换为像素以便用它。
  • scrollBy(x,y)的第一个参数应该取值为0,以防不明显

我自己并没有在Android中制作animation,但自从Honeycomb以来,有一个非常好的API,可能很容易做到这一点。

我很抱歉,但这是我能想到的最简单的!

编辑:从'dp'转换为像素:

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

你必须做的是用不同的'dp'值调用scrollBy(0,pxFromDp(dp)),直到你得到一个将NumberPicker移动一个数字的确切的值。 一旦你得到这个值,你可以创build你的animation方法,当向上移动X号码将滚动X倍这个Dp距离。

如果你不完全理解,请再问一次:)

感谢@passsy。 启发他的答案:这个解决scheme支持多个递增/递减步骤 。 此外,可以执行启动延迟多个编号(无需额外的编码)

 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. } } 

用法:

 // 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). 

NumberPicker里面有私有方法,

 changeCurrentByOne(boolean increment) 

你可以公开并使用它。 当按下NumberPicker的向上向下箭头时,您可以看到此方法正在执行。 也许这不是你正在寻找的,因为这种方法不能给予animation的太多控制,但它比setValue更好。 没有任何animationsetValue对用户来说看起来很糟糕。