如何用动画更改NumberPicker的值?

时间:2012-11-21 19:40:53

标签: android animation android-animation numberpicker

我已经为Android创建了一个应用程序,其中有一个NumberPicker。我需要更改此NumberPicker的值,但需要使用平滑动画,就像触摸它并更改其值一样。

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

如果我使用以下代码:

numberPicker.setValue(5);

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

6 个答案:

答案 0 :(得分:15)

我通过反思来解决它

        /**
         * 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();
            }
        }

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

答案 1 :(得分:3)

我不相信这是原生支持的。我想到了一种手动操作的“混乱”方式:

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

需要考虑的一些事项:

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

我自己没有在Android中制作动画,但是自Honeycomb以来有一个非常好的API,可能很容易实现这一点。

对不起,但这是我能想到的最容易的!

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

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

您需要做的是测试使用不同'dp'值调用scrollBy(0,pxFromDp(dp)),直到获得将NumberPicker移动一个数字的确切值。获得该值后,您可以创建一个动画方法,当向上移动X数字时,将滚动此dp距离的X倍。

如果您不完全理解,请再次询问:)

答案 2 :(得分:3)

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

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 (e.g. 100 milliseconds).

答案 3 :(得分:1)

NumberPicker中有私有方法,即

changeCurrentByOne(boolean increment)

您可以将其公开并使用它。按下NumberPicker的 UP DOWN 箭头时,您可以看到此方法的实际效果。可能它不是你想要的,因为这种方法不能很好地控制动画,但它确实比 setValue 更好。没有任何动画 setValue 对用户来说看起来很糟糕。

答案 4 :(得分:0)

感谢@passy的回答。可以使用Kotlin扩展功能进一步简化:

fun NumberPicker.animateChange(isIncrement: Boolean) {
    Handler().post {
        try {
            javaClass.getDeclaredMethod("changeValueByOne", Boolean::class.javaPrimitiveType).also { function ->
                function.isAccessible = true
                function.invoke(this, isIncrement)
            }
        } catch (e: Exception) {
            Log.e(javaClass.simpleName, e.message)
        }
    }
}

答案 5 :(得分:0)

致电

accessibilityNodeProvider.performAction(View.NO_ID, AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, null)

增加1

accessibilityNodeProvider.performAction(View.NO_ID, AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, null)

减少1