我创建的Android应用程序,其中有一个NumberPicker。 我需要改变这个NumberPicker的价值,但有一个流畅的动画效果,当你触摸它像并改变它的值。
例如,假设当前值是1,这将是5,我要NumberPicker旋转从1到2,然后以3等。 但我想它旋转不只是瞬间改变的值!
如果我使用下面的代码:
numberPicker.setValue(5);
它的价值会立即更改为5,但我想它从1卷起至5就像当你手动触摸它,使其旋转。
我创建的Android应用程序,其中有一个NumberPicker。 我需要改变这个NumberPicker的价值,但有一个流畅的动画效果,当你触摸它像并改变它的值。
例如,假设当前值是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)对函数调用的反复,使动画的效果。
有些事情要考虑:
我没有在Android的动画制作自己,但因为蜂窝很好的API,它大概可以很容易地做到这一点。
我很抱歉,但是这是我能想到的最简单的!
编辑:从“DP”的像素转换:
private float pxFromDp(float dp)
{
return dp * this.getContext().getResources().getDisplayMetrics().density;
}
什么你必须做的就是测试调用scrollBy(0,pxFromDp(DP))与不同的“DP”值,直到你得到确切的一个,最多一个数字移动NumberPicker。 一旦你得到的价值,你可以创建向上移动时,X号将滚动X倍这个DP距离你的动画方法。
请再次问,如果你不完全理解它:)
谢谢@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).
里面有NumberPicker,这是私有方法
changeCurrentByOne(boolean increment)
你可以把它公开,并使用它。 按UP或NumberPicker的向下箭头时,您可以在行动中看到这种方法。 也许这不是你在找什么,因为这种方法不会给动画的太多的控制,但它比definitelly更好的setValue。 没有任何动画的setValue看起来很可怕用户。
由于@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)
}
}
}