如何改变NumberPicker与动画的价值?(How to change NumberPicker

2019-07-04 00:56发布

我创建的Android应用程序,其中有一个NumberPicker。 我需要改变这个NumberPicker的价值,但有一个流畅的动画效果,当你触摸它像并改变它的值。

例如,假设当前值是1,这将是5,我要NumberPicker旋转从1到2,然后以3等。 但我想它旋转不只是瞬间改变的值!

如果我使用下面的代码:

numberPicker.setValue(5);

它的价值会立即更改为5,但我想它从1卷起至5就像当你手动触摸它,使其旋转。

Answer 1:

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

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



Answer 2:

我不相信,这是原生支持。 我想到了做手工的“凌乱”的方式:

您可以使用NumberPicker的scrollBy(INT X,int y)对函数调用的反复,使动画的效果。

有些事情要考虑:

  • scrollBy(X,Y)的作品与像素。 由于Android已经得到了所有不同的屏幕密度,你应该做的是第一个猜测对应于滚动到一个连续的值“DP”的距离(我的试验和错误做到这一点),并且将其转换成像素,以用它。
  • scrollBy(X,Y)的第一个参数应采取的值为0,在情况下,它并不明显

我没有在Android的动画制作自己,但因为蜂窝很好的API,它大概可以很容易地做到这一点。

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

编辑:从“DP”的像素转换:

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

什么你必须做的就是测试调用scrollBy(0,pxFromDp(DP))与不同的“DP”值,直到你得到确切的一个,最多一个数字移动NumberPicker。 一旦你得到的价值,你可以创建向上移动时,X号将滚动X倍这个DP距离你的动画方法。

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



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


Answer 4:

里面有NumberPicker,这是私有方法

changeCurrentByOne(boolean increment)

你可以把它公开,并使用它。 按UP或NumberPicker的向下箭头时,您可以在行动中看到这种方法。 也许这不是你在找什么,因为这种方法不会给动画的太多的控制,但它比definitelly更好的setValue。 没有任何动画的setValue看起来很可怕用户。



Answer 5:

由于@passy答案。 可以用科特林扩展功能进一步简化:

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


文章来源: How to change NumberPicker's value with animation?