我已经为Android创建了一个应用程序,其中有一个NumberPicker。我需要更改此NumberPicker的值,但需要使用平滑动画,就像触摸它并更改其值一样。
例如,假设当前值为1并且它将为5,我希望NumberPicker从1旋转到2然后旋转到3,依此类推。但我希望它不仅可以立即改变价值!
如果我使用以下代码:
numberPicker.setValue(5);
它的值会立即变为5,但我希望它从1到5卷起,就像手动触摸它并让它旋转一样。
答案 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)函数迭代调用以产生动画效果。
需要考虑的一些事项:
我自己没有在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